在https://blog.csdn.net/fengbingchun/article/details/93975325 中给出了通过旧接口即FFmpeg中已废弃的接口实现通过摄像头获取视频流然后解码并显示的测试代码,这里通过使用FFmpeg中的新接口再次实现通过的功能,主要涉及到的接口函数包括:

1. avdevice_register_all:初始化libavdevice库并注册所有输入输出设备;

2. av_find_input_format:根据输入格式的名字查找AVInputFormat,在测试代码中,windows平台使用”vfwcap”(video for windows capture),linux平台使用”v4l2”(Video4Linux2);

3. avformat_alloc_context:分配AVFormatContext;

4. av_dict_set:设置或重写一个AVDictionary项,测试代码中设置video_size为640x480,设置input_format为mjpeg,这两个设置仅对usb摄像头有效,对windows内置摄像头会crash;

5. avformat_open_input:打开输入流并读取header;

6. avformat_find_stream_info:读取媒体文件的数据包以获取流信息;

7. 通过AVFormatContext中AVStream查找视频/音频流索引,这里在windows10下获取到的编码类型为mjpeg即AV_CODEC_ID_MJPEG,像素格式为yuv422p即AV_PIX_FMT_YUVJ422P;在linux或windows7下获取到的原始编码类型为rawvideo即AV_CODEC_ID_RAWVIDEO,原始像素格式yuyv422即AV_PIX_FMT_YUYV422;由于通过av_dict_set进行了设置,因此编码类型由rawvideo调整成了mjpeg,可见可以通过av_dict_set对usb摄像头的原有配置进行调整;

8. avcodec_find_decoder:由codec ID查找已注册的解码器;

9. avcodec_alloc_context3:分配一个AVCodecContext并设置它的字段为默认值;

10. avcodec_open2:初始化AVCodecContext,由于前面使用avcodec_alloc_context3,因此在调用avcodec_open2之前,需要对AVCodecContext的某些字段进行指定值,如宽、高、像素格式等,thread_count用于指定几个线程来进行解码;

11. av_frame_alloc:分配一个AVFrame并设置它的字段为默认值;

12. av_malloc:为一个AVPacket分配内存块;

13. sws_getContext:分配一个SwsContext;

14. av_image_alloc:根据指定的宽、高、像素格式为图像分配buffer;

15. av_read_frame:获取流即packet(AVPacket);

16. avcodec_send_packet:提供原始packet数据作为解码器的输入;

17. avcodec_receive_frame:从解码器中获取解码后的数据;

18. sws_scale:转换图像格式;

19. av_packet_unref:释放AVPacket;

20. av_frame_free:释放由av_frame_alloc分配的AVFrame;

21. sws_freeContext:释放由sws_getContext分配的SwsContext;

22. av_freep:释放由av_malloc分配的AVPacket;

23. avformat_close_input:关闭打开的AVFormatContext并释放;

24. av_dict_free:释放由av_dist_set分配的AVDictionary;

25. av_freep:释放由av_image_alloc分配的buffer。

测试代码(test_ffmpeg_decode_show.cpp):

#include "funset.hpp"
#include <stdio.h>
#include <iostream>
#include <memory>
#include <fstream>#ifdef __cplusplus
extern "C" {
#endif#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/mem.h>
#include <libavutil/imgutils.h>#ifdef __cplusplus
}
#endif#include <opencv2/opencv.hpp>int test_ffmpeg_decode_show_new()
{avdevice_register_all();AVDictionary* options = nullptr;
#ifdef _MSC_VERconst char* input_format_name = "vfwcap";const char* url = "";
#elseconst char* input_format_name = "video4linux2";const char* url = "/dev/video0";av_dict_set(&options, "video_size", "640x480", 0);av_dict_set(&options, "input_format", "mjpeg", 0);
#endifAVInputFormat* input_fmt = av_find_input_format(input_format_name);AVFormatContext* format_ctx = avformat_alloc_context();int ret = avformat_open_input(&format_ctx, url, input_fmt, &options);if (ret != 0) {fprintf(stderr, "fail to open url: %s, return value: %d\n", url, ret);return -1;}ret = avformat_find_stream_info(format_ctx, nullptr);if (ret < 0) {fprintf(stderr, "fail to get stream information: %d\n", ret);return -1;}int video_stream_index = -1;for (unsigned int i = 0; i < format_ctx->nb_streams; ++i) {const AVStream* stream = format_ctx->streams[i];if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {video_stream_index = i;fprintf(stdout, "type of the encoded data: %d, dimensions of the video frame in pixels: width: %d, height: %d, pixel format: %d\n",stream->codecpar->codec_id, stream->codecpar->width, stream->codecpar->height, stream->codecpar->format);}}if (video_stream_index == -1) {fprintf(stderr, "no video stream\n");return -1;}AVCodecParameters* codecpar = format_ctx->streams[video_stream_index]->codecpar;const AVCodec* codec = avcodec_find_decoder(codecpar->codec_id);if (!codec) {fprintf(stderr, "fail to avcodec_find_decoder\n");return -1;}AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);if (!codec_ctx) {fprintf(stderr, "fail to avcodec_alloc_context3\n");return -1;}codec_ctx->pix_fmt = AVPixelFormat(codecpar->format);codec_ctx->height = codecpar->height;codec_ctx->width = codecpar->width;codec_ctx->thread_count = 4;ret = avcodec_open2(codec_ctx, codec, nullptr);if (ret != 0) {fprintf(stderr, "fail to avcodec_open2: %d\n", ret);return -1;}AVFrame* frame = av_frame_alloc();AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket));SwsContext* sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_BGR24, 0, nullptr, nullptr, nullptr);if (!frame || !packet || !sws_ctx) {fprintf(stderr, "fail to alloc\n");return -1;}uint8_t* bgr_data[4];int bgr_linesize[4];av_image_alloc(bgr_data, bgr_linesize, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_BGR24, 1);cv::Mat mat(codec_ctx->height, codec_ctx->width, CV_8UC3);const char* winname = "usb video2";cv::namedWindow(winname);while (1) {ret = av_read_frame(format_ctx, packet);if (ret >= 0 && packet->stream_index == video_stream_index) {ret = avcodec_send_packet(codec_ctx, packet);if (ret < 0) {fprintf(stderr, "fail to avcodec_send_packet: %d\n", ret);av_packet_unref(packet);continue;}ret = avcodec_receive_frame(codec_ctx, frame);if (ret < 0) {fprintf(stderr, "fail to avcodec_receive_frame\n");av_packet_unref(packet);continue;}sws_scale(sws_ctx, frame->data, frame->linesize, 0, codec_ctx->height, bgr_data, bgr_linesize);mat.data = bgr_data[0];cv::imshow(winname, mat);}av_packet_unref(packet);int key = cv::waitKey(25);if (key == 27) break;}cv::destroyWindow(winname);av_frame_free(&frame);sws_freeContext(sws_ctx);av_dict_free(&options);avformat_close_input(&format_ctx);av_freep(packet);av_freep(&bgr_data[0]);fprintf(stdout, "test finish\n");return 0;
}

执行结果如下:

GitHub:https://github.com//fengbingchun/OpenCV_Test

FFmpeg通过摄像头实现对视频流进行解码并显示测试代码(新接口)相关推荐

  1. FFmpeg通过摄像头实现对视频流进行解码并显示测试代码(旧接口)

    这里通过USB摄像头(注:windows7/10下使用内置摄像头,linux下接普通的usb摄像头(Logitech))获取视频流,然后解码,最后再用opencv显示.用到的模块包括avformat. ...

  2. FFmpeg中编码类型为rawvideo无须解码直接显示测试代码

    在 https://blog.csdn.net/fengbingchun/article/details/93975325 中介绍过通过FFmpeg可以直接获取usb视频流并解码显示的测试代码,当时通 ...

  3. FFmpeg中一个线程获取视频流一个线程执行scale测试代码

    在https://blog.csdn.net/fengbingchun/article/details/94712986 中介绍过如果usb视频流编码类型为rawvideo则无需进行解码,可直接通过a ...

  4. FFmpeg在Windows上通过dshow编解码方式设置为mjpeg并实时显示测试代码

    Windows上默认的内置摄像头一般支持两种编解码格式:rawvideo和mjpeg.在调用FFmpeg接口时默认的采用rawvideo.这里通过DirectShow实现为mjpeg进行编解码. 通过 ...

  5. FFmpeg在Windows上设置dshow mjpeg编码+libyuv解码显示测试代码

    之前在https://blog.csdn.net/fengbingchun/article/details/103444891中介绍过在Windows上通过ffmpeg dshow设置为mjpeg编解 ...

  6. FFmpeg中拉取rtsp视频流并缩放显示测试代码

    之前在https://blog.csdn.net/fengbingchun/article/details/92198857中给出过仅拉取rtsp视频流的测试代码,这里在此代码的基础上进行扩充,包括设 ...

  7. ffmpeg+nvidia解码SDK+GPU实现视频流硬解码成Mat

    方法原理 rtsp流解码方式分为两种:硬解码和软解码.软解码一般通过ffmpeg编解码库实现,但是cpu占用率很高,解码一路1080p视频cpu占用率达到70%左右,对实际应用来说,严重影响机器最大解 ...

  8. FFmpeg实现获取USB摄像头视频流测试代码

    通过USB摄像头(注:windows7/10下使用内置摄像头,linux下接普通的usb摄像头(Logitech))获取视频流用到的模块包括avformat和avdevice.头文件仅include ...

  9. FFMPEG采集摄像头图像SDL渲染+MP4格式视频编码

    FFMPEG采集摄像头图像SDL渲染+MP4格式视频编码 FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.采用LGPL或GPL许可证.它提供了录制.转换以及流化音 ...

最新文章

  1. c语言求n个数的最小值博客,C语言中的#define宏定义 求一组数的最大值和最小值(转)...
  2. excel mysql日报_Excel日报自动化
  3. [裴礼文数学分析中的典型问题与方法习题参考解答]4.3.13
  4. 如何更快地将string转换成int/long
  5. python程序设计报告-20183122 实验一《Python程序设计》实验报告
  6. orb 算法源码实现
  7. OpenStack创建win7实例遇到的问题(尚未解决,求帮助)
  8. ios开发ios9新特性关键字学习:泛型,逆变,协变,__kindof
  9. Python(入门小练习1)
  10. 【Three.js】模型抗锯齿处理
  11. AD(PCB)知识总结
  12. 基于vue和springboot的物流仓储管理系统
  13. SPSS-描述统计与图示分析
  14. 基于HTML和CSS完成京东页面的制作
  15. 路由器和交换机常见故障信息收集命令总结
  16. kubernetes之ReplicaSet
  17. mysql报08s01的错误_MYSQL报08S01的异常
  18. 【JD1-100漏电继电器】
  19. 百度开源项目BFE-BFE总览
  20. java毕业设计的创意项目众筹平台的设计与开发(附源码、数据库)

热门文章

  1. OpenCV中的霍夫线变换、概率霍夫线变换
  2. OpenCV中的立体图像创建深度图
  3. C++:多线程中的小白(1)基础概念
  4. LabVIEW OCR 实现车牌识别(实战篇—3)
  5. github分段下载
  6. php多线程模型,PHP进程模型、进程通讯方式、进程线程的区别分别有哪些?
  7. 可见光能量范围_通过能量转移技术实现双功能金属有机框架中分子马达的可见光驱动旋转...
  8. Python中if__name__==__main__:该如何理解
  9. Learn OpenGL (三):着色器
  10. JUnit单元测试依赖包构建路径错误解决办法