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

发布时间:2021-09-27 10:03:26 作者:小新
来源:亿速云 阅读:164

这篇文章主要介绍了FFmpeg如何获取网络摄像头数据解码,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

对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:jdh223456@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:jdh223456@10.170.6.187,这里是摄像头的名称和IP地址。

感谢你能够认真阅读完这篇文章,希望小编分享的“FFmpeg如何获取网络摄像头数据解码”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!

推荐阅读:
  1. FFMPEG 视频图像解封装解码
  2. FFMPEG4.0 音频解码解封装

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

ffmpeg

上一篇:Ubuntu 15.04系统安装后有哪些需要注意的问题

下一篇:如何配置accesslog以及accesslog 的各种占位符

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》