FFmpeg --12-packet数据包和frame数据帧的区别

基本概念

数据包(packet),是存储压缩编码数据的基本单位,在音频编码中,通常一个数据包只包含一帧数据,在视频编码中,由于B帧和P帧的存在,可以出现一个数据包包含多帧数据的情况

数据帧(frame), 存储非压缩数据的基本单位,对于视频为yuv 或者 rgb , 音频为aac数据

结构体字段:

Frame:

  • data[AV_NUM_DATA_POINTERS]:存放解码后的原始媒体数据的指针数组,
    对于视频数据,planar格式中, Y、U、V分量会被分别存放在data[0]、data[1]、data[2] ,packet格式的数据会被存放在data[0]中。
    对于音频数据,channel的不同声道分别存储在data[0]、data[1]等

AVPacket:

  • buf:指向数据包内存的引用。
  • pts 和 dts:分别代表显示时间戳和解码时间戳。
  • data 和 size:指向数据包的数据和大小。
  • stream_index:该数据包属于哪个流。

主要函数

获取音频/视频包:

int av_read_frame(AVFormatContext *s, AVPacket *pkt);
// pkt 为解析后获取的数据包

AVPacket *pkt = av_packet_alloc();
while (1)
    {
        av_read_frame(ifmt_ctx, pkt);
        av_packet_unref(pkt);
    }
    if(pkt)
        av_packet_free(&pkt);

获取音频/视频帧:

int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);


AVFrame *pFrame = av_frame_alloc(); 
while(){
	av_receive_frame(ctx, pFrame);
	//...
	av_frame_unref(pFrame);         
} 
av_frame_free(pFrame);             
参考提供的引用内容,未提及将ffmpeg - rockchip解码后的数据转换为opencv格式的方法。不过,一般情况下,要实现这一转换可以按以下通用思路进行: ### 步骤 1. **解码视频帧**:使用FFmpeg - Rockchip进行视频解码,得到原始的视频帧数据(如YUV格式)。 2. **格式转换**:将解码后的YUV格式数据转换为OpenCV支持的BGR格式。可以使用FFmpeg的`sws_scale`函数进行颜色空间转换。 3. **创建OpenCV的Mat对象**:将转换后的BGR数据存储到OpenCV的`cv::Mat`对象中。 ### 代码示例 ```cpp #include <opencv2/opencv.hpp> #include <iostream> #include <string> extern "C" { #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> } int main() { // 初始化FFmpeg avformat_network_init(); av_register_all(); avcodec_register_all(); // 打开输入文件 AVFormatContext* formatContext = nullptr; if (avformat_open_input(&formatContext, "input.mp4", nullptr, nullptr) != 0) { std::cerr << "Could not open input file" << std::endl; return -1; } // 查找流信息 if (avformat_find_stream_info(formatContext, nullptr) < 0) { std::cerr << "Could not find stream information" << std::endl; return -1; } // 查找视频流 int videoStreamIndex = -1; AVCodecParameters* codecParameters = nullptr; for (unsigned int i = 0; i < formatContext->nb_streams; i++) { if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { videoStreamIndex = i; codecParameters = formatContext->streams[i]->codecpar; break; } } if (videoStreamIndex == -1) { std::cerr << "Could not find video stream" << std::endl; return -1; } // 查找解码器 AVCodec* codec = avcodec_find_decoder(codecParameters->codec_id); if (!codec) { std::cerr << "Could not find codec" << std::endl; return -1; } // 分配解码器上下文 AVCodecContext* codecContext = avcodec_alloc_context3(codec); if (!codecContext) { std::cerr << "Could not allocate codec context" << std::endl; return -1; } // 将参数复制到解码器上下文 if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) { std::cerr << "Could not copy codec parameters to context" << std::endl; return -1; } // 打开解码器 if (avcodec_open2(codecContext, codec, nullptr) < 0) { std::cerr << "Could not open codec" << std::endl; return -1; } // 分配AVFrame用于存储解码后的帧 AVFrame* frame = av_frame_alloc(); if (!frame) { std::cerr << "Could not allocate frame" << std::endl; return -1; } // 分配AVPacket用于存储压缩数据 AVPacket* packet = av_packet_alloc(); if (!packet) { std::cerr << "Could not allocate packet" << std::endl; return -1; } // 初始化SwsContext用于颜色空间转换 SwsContext* swsContext = sws_getContext(codecContext->width, codecContext->height, codecContext->pix_fmt, codecContext->width, codecContext->height, AV_PIX_FMT_BGR24, SWS_BILINEAR, nullptr, nullptr, nullptr); if (!swsContext) { std::cerr << "Could not initialize SwsContext" << std::endl; return -1; } // 读取并解码帧 while (av_read_frame(formatContext, packet) >= 0) { if (packet->stream_index == videoStreamIndex) { // 发送数据包到解码器 if (avcodec_send_packet(codecContext, packet) < 0) { std::cerr << "Error sending packet to decoder" << std::endl; continue; } // 接收解码后的帧 while (avcodec_receive_frame(codecContext, frame) == 0) { // 分配OpenCV的Mat对象 cv::Mat cvFrame(frame->height, frame->width, CV_8UC3); // 分配AVFrame用于存储BGR数据 AVFrame* bgrFrame = av_frame_alloc(); if (!bgrFrame) { std::cerr << "Could not allocate BGR frame" << std::endl; continue; } // 分配缓冲区 int numBytes = av_image_get_buffer_size(AV_PIX_FMT_BGR24, frame->width, frame->height, 1); uint8_t* buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t)); av_image_fill_arrays(bgrFrame->data, bgrFrame->linesize, buffer, AV_PIX_FMT_BGR24, frame->width, frame->height, 1); // 进行颜色空间转换 sws_scale(swsContext, frame->data, frame->linesize, 0, frame->height, bgrFrame->data, bgrFrame->linesize); // 将数据复制到OpenCV的Mat对象 for (int y = 0; y < frame->height; y++) { memcpy(cvFrame.ptr(y), bgrFrame->data[0] + y * bgrFrame->linesize[0], frame->width * 3); } // 显示图像 cv::imshow("Decoded Frame", cvFrame); cv::waitKey(25); // 释放资源 av_free(buffer); av_frame_free(&bgrFrame); } } av_packet_unref(packet); } // 释放资源 sws_freeContext(swsContext); av_frame_free(&frame); av_packet_free(&packet); avcodec_close(codecContext); avformat_close_input(&formatContext); return 0; } ``` 上述代码展示了如何使用FFmpeg进行视频解码,并将解码后的YUV数据转换为OpenCV支持的BGR格式,存储到`cv::Mat`对象中。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

八月的雨季997

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值