日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

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

發布時間:2023/11/27 生活经验 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FFmpeg通过摄像头实现对视频流进行解码并显示测试代码(新接口) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在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通过摄像头实现对视频流进行解码并显示测试代码(新接口)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。