FFmpeg中拉取rtsp视频流并缩放显示测试代码
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                FFmpeg中拉取rtsp视频流并缩放显示测试代码
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                之前在https://blog.csdn.net/fengbingchun/article/details/92198857中給出過僅拉取rtsp視頻流的測試代碼,這里在此代碼的基礎上進行擴充,包括設置使用多線程進行解碼,使用sws_scale函數進行圖像格式轉換和縮放,并通過OpenCV進行顯示,測試代碼如下:
#include "funset.hpp"
#include <iostream>#ifdef __cplusplus
extern "C" {
#endif#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>#ifdef __cplusplus
}
#endif#include <opencv2/opencv.hpp>
#include "common.hpp"int test_ffmpeg_rtsp_client_decode_show()
{const char* url = "rtsp://184.72.239.149/vod/mp4://BigBuckBunny_115k.mov";AVFormatContext* format_ctx = avformat_alloc_context();int ret = avformat_open_input(&format_ctx, url, nullptr, nullptr);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, audio_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);} else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {audio_stream_index = i;fprintf(stdout, "audio sample format: %d\n", stream->codecpar->format);}}if (video_stream_index == -1) {fprintf(stderr, "no video stream\n");return -1;}if (audio_stream_index == -1) {fprintf(stderr, "no audio stream\n");}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 = 16;ret = avcodec_open2(codec_ctx, codec, nullptr);if (ret != 0) {fprintf(stderr, "fail to avcodec_open2: %d\n", ret);return -1;}const int width_new = 640, height_new = 480;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, width_new, height_new, AV_PIX_FMT_BGR24, SWS_BICUBIC, 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, width_new, height_new, AV_PIX_FMT_BGR24, 1);cv::Mat mat(height_new, width_new, CV_8UC3);const char* winname = "rtst video";cv::namedWindow(winname);long long time_begin, time_end;while (1) {//time_begin = Timer::getNowTime();ret = av_read_frame(format_ctx, packet);//time_end = Timer::getNowTime();//fprintf(stdout, "av_read_frame cost time: %lldms\n", time_end - time_begin);if (ret >= 0 && packet->stream_index == video_stream_index && packet->size > 0) {//time_begin = Timer::getNowTime();ret = avcodec_send_packet(codec_ctx, packet);//time_end = Timer::getNowTime();//fprintf(stdout, "avcodec_send_packet cost time: %lldms\n", time_end - time_begin);if (ret < 0) {fprintf(stderr, "##### fail to avcodec_send_packet: %d\n", ret);av_packet_unref(packet);continue;}//time_begin = Timer::getNowTime();ret = avcodec_receive_frame(codec_ctx, frame);//time_end = Timer::getNowTime();//fprintf(stdout, "avcodec_receive_frame cost time: %lldms\n", time_end - time_begin);if (ret < 0) {fprintf(stderr, "##### fail to avcodec_receive_frame: %d\n", ret);av_packet_unref(packet);continue;}//time_begin = Timer::getNowTime();sws_scale(sws_ctx, frame->data, frame->linesize, 0, codec_ctx->height, bgr_data, bgr_linesize);//time_end = Timer::getNowTime();//fprintf(stdout, "sws_scale cost time: %lldms\n", time_end - time_begin);mat.data = bgr_data[0];cv::imshow(winname, mat);} else if (ret < 0 || packet->size <= 0) {fprintf(stderr, "##### fail to av_read_frame: %d, packet size: %d\n", ret, packet->size);continue;}av_packet_unref(packet);int key = cv::waitKey(10);if (key == 27) break;}cv::destroyWindow(winname);av_frame_free(&frame);sws_freeContext(sws_ctx);avformat_close_input(&format_ctx);av_freep(packet);av_freep(&bgr_data[0]);fprintf(stdout, "test finish\n");return 0;
}執行結果如下:拉取到的rtsp視頻流,編碼類型為H264,像素格式為YUV420P,原始大小為240x160,通過sws_scale將像素格式轉換為bgr24并縮放到640x480顯示。
GitHub:https://github.com/fengbingchun/OpenCV_Test
總結
以上是生活随笔為你收集整理的FFmpeg中拉取rtsp视频流并缩放显示测试代码的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 海思3559A上编译FFmpeg源码操作
- 下一篇: V4L2获取usb视频流测试代码
