关于解码后的data与linesize的关系

AVPicture里面有data[4]和linesize[4]其中data是一个指向指针的指针(二级、二维指针),也就是指向视频数据缓冲区的首地址,而data[0]~data[3]是一级指针,可以用如下的图来表示:


data -->xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        ^                ^              ^
        |                |              |
         data[0]      data[1]         data[2]

比如说,当pix_fmt=PIX_FMT_YUV420P时,data中的数据是按照YUV的格式存储的,也就是:

data -->YYYYYYYYYYYYYYUUUUUUUUUUUUUVVVVVVVVVVVV
        ^                ^              ^
        |                |              |
         data[0]      data[1]         data[2]

linesize是指对应于每一行的大小,为什么需要这个变量,是因为在YUV格式和RGB格式时,每行的大小不一定等于图像的宽度,对于RGB格式输出时,只有一个通道(bgrbgrbgr......)可用,即linesize[0],和data[0],so RGB24 : data[0] = packet rgb//bgrbgrbgr......

linesize[0] = width*3

其他的如data[1][2][3]与linesize[1][2][3]无任何意义.

而对于YUV格式输出时,有三个通道可用,即data[0][1][2],与linesize[0][1][2],而yuv格式对于运动估计时,需要填充padding(right, bottom),故:

linesize=width+padding size(16+16).

有关该问题的讨论帖可参考ffmpeg工程组论坛中的相关讨论:

使用FFmpeg进行解码和重新编码需要以下步骤: 1. 初始化FFmpeg库 在使用FFmpeg之前,需要初始化库。可以使用av_register_all()函数进行初始化。 2. 打开输入文件并获取相关信息 使用avformat_open_input()函数打开输入文件,并使用avformat_find_stream_info()函数获取文件流信息。 3. 查找视频流 使用av_find_best_stream()函数查找视频流,并获取视频流索引。 4. 创建解码器上下文 使用avcodec_find_decoder()函数查找解码器,并创建解码器上下文。 5. 打开解码器 使用avcodec_open2()函数打开解码器。 6. 创建编码器上下文 使用avcodec_find_encoder()函数查找编码器并创建编码器上下文。 7. 设置编码器参数 设置编码器参数,如编码格式、视频宽度和高度等。 8. 打开编码器 使用avcodec_open2()函数打开编码器。 9. 创建输出文件 使用avformat_alloc_output_context2()函数创建输出文件。 10. 写入文件头信息 使用avformat_write_header()函数写入文件头信息。 11. 解码并编码每一帧 使用av_read_frame()函数读取每一帧数据,使用avcodec_send_packet()函数发送数据到解码器,使用avcodec_receive_frame()函数接收解码后的帧数据,将解码后的帧数据发送到编码器,使用avcodec_send_frame()函数发送数据到编码器,使用avcodec_receive_packet()函数接收编码后的数据,将编码后的数据写入输出文件。 12. 写入文件尾信息 使用av_write_trailer()函数写入文件尾信息。 13. 释放资源 释放所有资源,包括解码器上下文、编码器上下文、输入文件和输出文件。 以下是一个简单的示例代码: ``` #include <iostream> #include <string> #include <fstream> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/imgutils.h> #include <libswscale/swscale.h> } int main(int argc, char *argv[]) { // 初始化FFmpeg库 av_register_all(); // 打开输入文件并获取相关信息 AVFormatContext *inputFormatCtx = nullptr; if (avformat_open_input(&inputFormatCtx, argv[1], nullptr, nullptr) < 0) { std::cout << "Could not open input file" << std::endl; return -1; } if (avformat_find_stream_info(inputFormatCtx, nullptr) < 0) { std::cout << "Could not find stream info" << std::endl; return -1; } // 查找视频流 int videoStreamIndex = av_find_best_stream(inputFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0); if (videoStreamIndex < 0) { std::cout << "Could not find video stream" << std::endl; return -1; } // 创建解码器上下文 AVCodec *decoder = avcodec_find_decoder(inputFormatCtx->streams[videoStreamIndex]->codecpar->codec_id); AVCodecContext *decoderCtx = avcodec_alloc_context3(decoder); if (avcodec_parameters_to_context(decoderCtx, inputFormatCtx->streams[videoStreamIndex]->codecpar) < 0) { std::cout << "Failed to copy codec parameters to decoder context" << std::endl; return -1; } // 打开解码器 if (avcodec_open2(decoderCtx, decoder, nullptr) < 0) { std::cout << "Failed to open decoder" << std::endl; return -1; } // 创建编码器上下文 AVCodec *encoder = avcodec_find_encoder(AV_CODEC_ID_H264); AVCodecContext *encoderCtx = avcodec_alloc_context3(encoder); if (!encoderCtx) { std::cout << "Could not allocate encoder context" << std::endl; return -1; } // 设置编码器参数 encoderCtx->bit_rate = 400000; encoderCtx->width = decoderCtx->width; encoderCtx->height = decoderCtx->height; encoderCtx->time_base = decoderCtx->time_base; encoderCtx->framerate = decoderCtx->framerate; encoderCtx->gop_size = 10; encoderCtx->max_b_frames = 1; encoderCtx->pix_fmt = AV_PIX_FMT_YUV420P; // 打开编码器 if (avcodec_open2(encoderCtx, encoder, nullptr) < 0) { std::cout << "Failed to open encoder" << std::endl; return -1; } // 创建输出文件 AVFormatContext *outputFormatCtx = nullptr; if (avformat_alloc_output_context2(&outputFormatCtx, nullptr, nullptr, argv[2]) < 0) { std::cout << "Could not allocate output format context" << std::endl; return -1; } // 写入文件头信息 if (avformat_write_header(outputFormatCtx, nullptr) < 0) { std::cout << "Failed to write header" << std::endl; return -1; } AVPacket packet; av_init_packet(&packet); // 解码并编码每一帧 while (true) { AVFrame *frame = av_frame_alloc(); if (!frame) { std::cout << "Could not allocate frame" << std::endl; return -1; } if (av_read_frame(inputFormatCtx, &packet) < 0) { break; } if (packet.stream_index != videoStreamIndex) { av_packet_unref(&packet); continue; } int ret = avcodec_send_packet(decoderCtx, &packet); if (ret < 0) { std::cout << "Error sending a packet for decoding" << std::endl; return -1; } while (ret >= 0) { ret = avcodec_receive_frame(decoderCtx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { av_frame_unref(frame); break; } else if (ret < 0) { std::cout << "Error during decoding" << std::endl; return -1; } AVFrame *encoderFrame = av_frame_alloc(); if (!encoderFrame) { std::cout << "Could not allocate encoder frame" << std::endl; return -1; } encoderFrame->format = encoderCtx->pix_fmt; encoderFrame->width = encoderCtx->width; encoderFrame->height = encoderCtx->height; encoderFrame->pts = frame->pts; ret = av_frame_get_buffer(encoderFrame, 32); if (ret < 0) { std::cout << "Could not allocate the encoder frame" << std::endl; return -1; } SwsContext *swsCtx = sws_getContext(decoderCtx->width, decoderCtx->height, decoderCtx->pix_fmt, encoderCtx->width, encoderCtx->height, encoderCtx->pix_fmt, SWS_BILINEAR, nullptr, nullptr, nullptr); sws_scale(swsCtx, frame->data, frame->linesize, 0, decoderCtx->height, encoderFrame->data, encoderFrame->linesize); sws_freeContext(swsCtx); ret = avcodec_send_frame(encoderCtx, encoderFrame); if (ret < 0) { std::cout << "Error sending a frame for encoding" << std::endl; return -1; } while (ret >= 0) { ret = avcodec_receive_packet(encoderCtx, &packet); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { av_packet_unref(&packet); break; } else if (ret < 0) { std::cout << "Error during encoding" << std::endl; return -1; } // 将编码后的数据写入输出文件 av_interleaved_write_frame(outputFormatCtx, &packet); } av_frame_free(&encoderFrame); av_frame_unref(frame); } av_packet_unref(&packet); } // 写入文件尾信息 av_write_trailer(outputFormatCtx); // 释放资源 avcodec_free_context(&decoderCtx); avcodec_free_context(&encoderCtx); avformat_close_input(&inputFormatCtx); avformat_free_context(outputFormatCtx); return 0; } ``` 注意:上述示例代码仅供参考,具体实现可能因为编解码格式等原因而有所不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值