FFmpeg获取网络摄像头数据解码

 更新时间:2020年4月25日 17:25  点击:1385

对USB摄像头实时编码,在前面已经探讨过了。这次改变下思路,尝试去截取网络摄像头的H264码流,将其解码播放。

这里的测试代码,是在海康摄像头的基础上进行的。

解码的大致流程和以前的保持一致,只不过增加了部分函数。

FFmpeg打开媒体文件并查看媒体文件的信息,有三个步骤:

avformat_open_input;

avformat_find_stream_info;

av_dump_format;

依次调用三个函数后,我们可以很清楚的知道码流的各种信息。

完整的代码:

#include <stdio.h>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <windows.h>
#include "queue.h"
 
extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
 
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib") 
#pragma comment(lib ,"swscale.lib")
 
using namespace std;
using namespace cv;
 
DWORD WINAPI opencv_imshow(LPVOID lparam)
{
 result_link_type* result_link = (result_link_type*)lparam;
 struct result_node_datatype *result_node2 = NULL;
 while (1)
 {
 result_node2 = result_pop(result_link);
 if (result_node2 == NULL)
 {
 Sleep(1);
 continue;
 }
 imshow("frame", result_node2->result);
 waitKey(1);
 }
}
 
int main(int argc, const char * argv[])
{
 HANDLE thread1;
 result_link_type *result_link = new result_link_type;
 result_link->head = result_link->end = NULL;
 result_link->result_num = 0;
 thread1 = CreateThread(NULL, 0, opencv_imshow, (LPVOID)result_link, 0, NULL);
 
 int i;
 int videoStream;
 int frameFinished;
 int numBytes;
 int ret;
 int got_picture;
 long prepts = 0;
 bool first_time = true;
 
 AVCodec *pCodec;
 AVFrame *pFrame;
 AVFrame *pFrameRGB;
 AVPacket packet;
 AVCodecContext *pCodecCtx;
 AVFormatContext *pFormatCtx = NULL;//结构体AVFormatContext:包含码流参数较多
 
 static struct SwsContext *img_convert_ctx;
 
 uint8_t *buffer;
 Mat pCvMat;
 
 char filepath[] = "rtsp://admin:jdh123456@10.170.6.187/axis-media/media.amp?camera=2";//码流的获取路径
 
 av_register_all();//注册编解码器
 avformat_network_init();//加载socket库以及网络加密协议相关的库
 
 if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0)//打开多媒体数据并且获得信息
 {
 return -1;
 }
 
 if (avformat_find_stream_info(pFormatCtx, NULL) < 0)//读取视音频数据并且获得信息
 {
 return -1;
 }
 
 av_dump_format(pFormatCtx, 0, argv[1], false);//手工调试函数,看到pFormatCtx->streams的内容
 
 videoStream = -1;
 
 for (i = 0; i < pFormatCtx->nb_streams; i++)
 {
 if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
 {
 videoStream = i;
 break;
 }
 }
 
 if (videoStream == -1)
 {
 return -1;
 }
 
 pCodecCtx = pFormatCtx->streams[videoStream]->codec;
 
 pCodec = avcodec_find_decoder(pCodecCtx->codec_id);//查找解码器
 
 if (pCodec == NULL)
 {
 return -1;
 }
 
 if (avcodec_open2(pCodecCtx, pCodec, 0) < 0)//初始化AVCodecContext
 {
 return -1;
 }
 
 if (pCodecCtx->time_base.num > 1000 && pCodecCtx->time_base.den == 1)
 {
 pCodecCtx->time_base.den = 1000;
 }
 
 pFrame = av_frame_alloc();//分配内存
 pFrameRGB = av_frame_alloc();
 
 i = 0;
 while (1)
 {
 if (av_read_frame(pFormatCtx, &packet) >= 0)//读取码流中的音频若干帧或者视频一帧
 {
 if (packet.stream_index == videoStream)
 {
 ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);//开始解码
 if (ret < 0)
 {
  printf("Decode Error.(解码错误)\n");
  return ret;
 }
 if (got_picture)//解码成功,got_picture返回任意非零值
 {
  if (first_time)
  {
  //初始化SwsContext
  img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
  if (img_convert_ctx == NULL)
  {
  fprintf(stderr, "Cannot initialize the conversion context!\n");
  exit(1);
  }
 
  numBytes = avpicture_get_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
  buffer = (uint8_t *)av_malloc(numBytes);
  avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); // allocator memory for BGR buffer 
  pCvMat.create(cv::Size(pCodecCtx->width, pCodecCtx->height), CV_8UC3);
  first_time = false;
  }
 
  //处理图像数据
  sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
  memcpy(pCvMat.data, buffer, numBytes);
  struct result_node_datatype *result_node = new struct result_node_datatype;
  result_node->result = pCvMat;
  result_push(result_link, result_node);
 }
 }
 av_free_packet(&packet);
 }
 }
 
 //free(buffer);
 av_free(buffer);
 av_free(pFrameRGB);
 av_free(pFrame);
 avcodec_close(pCodecCtx);
 avformat_close_input(&pFormatCtx);
 system("Pause");
 return 0;
}

队列函数:

#include "queue.h"
#include <iostream>
 
using namespace std;
 
void result_push(result_link_type* result_link, result_node_datatype * result_node) //入队操作
{
 if (result_link->head == NULL)
 {
 result_link->head = result_node;
 result_link->end = result_link->head;
 result_link->result_num++;
 }
 else
 {
 result_link->end->next = result_node;
 result_link->end = result_node;
 result_link->result_num++;
 }
}
 
struct result_node_datatype* result_pop(result_link_type* result_link) //出队操作
{
 struct result_node_datatype* tmp_node;
 if (result_link->head == NULL)
 return NULL;
 else if (result_link->head == result_link->end)
 {
 return NULL;
 }
 else
 {
 tmp_node = result_link->head;
 result_link->head = result_link->head->next;
 result_link->result_num--;
 return tmp_node;
 }
}

队列函数的头文件:

#ifndef QUEUE_H
#define QUEUE_H
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
 
typedef struct result_link_datatype
{
 struct result_node_datatype *head;
 struct result_node_datatype *end;
 int result_num;
}result_link_type;
 
struct result_node_datatype
{
 Mat result;
 struct result_node_datatype* next;
};
 
void result_push(result_link_type* result_link, result_node_datatype * result_node); //入队操作
struct result_node_datatype* result_pop(result_link_type* result_link);//出队操作
 
#endif

解码后的数据进入队列,再从队列中取出,利用opencv将其显示(opencv显示是另外开的一个线程函数)。

admin:jdh123456@10.170.6.187,这里是摄像头的名称和IP地址。

测试代码下载:点击打开链接

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • js实现调用网络摄像头及常见错误处理

    这篇文章主要介绍了js实现调用网络摄像头及常见错误处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-07
  • C#调用摄像头实现拍照功能的示例代码

    这篇文章主要介绍了C#调用摄像头实现拍照功能的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-12-08
  • php利用ffmpeg提取视频中音频与视频

    本篇文章为大家介绍了PHP利用ffmpeg提取视频中音频与视频画面的相关资料,很有参考价值,一起来看一看吧。 前言FFmpeg的名称来自MPEG视频编码标准,前面的“FF”代表...2017-07-06
  • unity3d调用手机或电脑摄像头

    这个是在网上看到的,经测试可以在电脑上运行,确实调用了本地摄像头。有需要的小伙伴可以参考下。...2020-06-25
  • 双摄像头手机对比:LG G5真的比华为P9强很多吗?

    现在采用后置双摄像头的手机越来越多,到底哪款双摄像头手机的拍照效果更好呢?这次我们就找来华为P9以及LG G5两款后置双摄像头手机来做对比,看看两者之间的差异,以及各自的独特之处。希望这次对比能够在你选择手机时起到一些帮助吧。...2016-07-04
  • Vue实现调用PC端摄像头实时拍照

    这篇文章主要为大家详细介绍了Vue实现调用PC端摄像头实时拍照,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-30
  • 教你如何用python操作摄像头以及对视频流的处理

    这篇文章主要介绍了教你如何用python操作摄像头以及对视频流的处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-12
  • C#实现通过ffmpeg从flv视频文件中截图的方法

    这篇文章主要介绍了C#实现通过ffmpeg从flv视频文件中截图的方法,实例分析了C#使用ffmpeg操作flv文件的技巧,需要的朋友可以参考下...2020-06-25
  • 基于AForge实现C#摄像头视频录制功能

    这篇文章主要为大家详细介绍了基于AForge实现C#摄像头视频录制功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • c#实现摄像头拍照功能示例

    这篇文章主要介绍了c#实现摄像头拍照功能示例,需要的朋友可以参考下...2020-06-25
  • 基于OpenCV读取摄像头实现单个人脸验证MFC程序

    这篇文章主要为大家详细介绍了基于OpenCV读取摄像头实现单个人脸验证MFC程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • python 基于opencv操作摄像头

    这篇文章主要介绍了python 基于opencv操作摄像头的方法,帮助大家更好的理解和使用python,感兴趣的朋友可以了解下...2020-12-24
  • C# 利用AForge实现摄像头信息采集

    这篇文章主要介绍了C# 如何利用AForge实现摄像头信息采集,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-11-03
  • C#实现调用本机摄像头实例

    这篇文章主要介绍了C#实现调用本机摄像头的方法,可以实现调用本机摄像头进行拍照,具有不错的实用价值,需要的朋友可以参考下...2020-06-25
  • opencv摄像头捕获识别颜色

    这篇文章主要介绍了opencv摄像头捕获识别颜色,用opencv通过摄像头捕获识别颜色,红色蓝色等,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • 双摄像头一定比单摄像头好吗?2016年五款热门拍照单镜头手机点评

    随着手机相机技术的不断成熟,如今智能手机的拍照虽然还不能说取代单反,但一些顶级拍照手机也基本能达到微单八成水平,对于满足用户日常拍摄足够了。下面小编就为大家带来2016年五款热门拍照单镜头手机点评,看看双摄像头一定比单摄像头好吗...2016-12-21
  • 爆猛料:传三星S8将使用双摄像头

    据外媒报道,三星旗舰手机GALAXY S7发布仅仅过去几个月,现在关于GALAXY S8的传闻就已经满天飞了。日前有爆料称,三星GALAXY S8将会配备双镜头,同时两枚镜头旁边还开了两个小孔,但暂时不清楚具体的作用。...2016-07-04
  • php利用ffmpeg提取视频中音频与视频画面的方法详解

    想要提取视频中的音频信息,首选的技术是ffmpeg,ffmpeg是一个非常有用的命令行程序,它可以用来转码媒体文件。这篇文章主要给大家介绍了PHP利用ffmpeg提取视频中音频与视频画面的相关资料,需要的朋友可以参考下。...2017-06-11
  • 苹果都在用 但双摄像头你真的了解吗?

    【手机中国 评测】继指纹识别成为手机的标配之后,双摄像头也成为厂商们新的“风向标”。搭载双摄像头的手机也逐渐多了起来,甚至是苹果公司也推出了双镜头设计的iPhone 7 Plus。那么,什么原因让厂商们对于双镜头如此趋之若鹜呢?...2016-09-28
  • 利用nginx与ffmpeg搭建流媒体服务器过程详解

    这篇文章主要给大家介绍了利用nginx与ffmpeg搭建流媒体服务器的全过程,文中介绍的很详细,对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。...2017-07-06