mediacodec编解码少帧问题

原文:http://blog.csdn.net/u011270282/article/details/50771515


使用mediacodec编解码,发现跟输入帧数不对,后面少了几帧,原因:

End-of-stream Handling

When you reach the end of the input data, you must signal it to the codec by specifying the BUFFER_FLAG_END_OF_STREAM flag in the call to queueInputBuffer. You can do this on the last valid input buffer, or by submitting an additional empty input buffer with the end-of-stream flag set. If using an empty buffer, the timestamp will be ignored.

The codec will continue to return output buffers until it eventually signals the end of the output stream by specifying the same end-of-stream flag in the MediaCodec.BufferInfo set in dequeueOutputBuffer or returned via onOutputBufferAvailable. This can be set on the last valid output buffer, or on an empty buffer after the last valid output buffer. The timestamp of such empty buffer should be ignored.

Do not submit additional input buffers after signaling the end of the input stream, unless the codec has been flushed, or stopped and restarted.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MediaCodec 是 Android 平台上的一个多媒体编解码器,用于对视频和音频进行编解码处理。由于 MediaCodec 是 Android 平台独有的 API,因此 C++ 直接调用 MediaCodec 进行视频解码可能不太方便。不过,如果你仍然想要使用 C++ 编写 MP4 文件解码为 YUV 格式的程序,可以考虑以下步骤: 1. 使用 FFmpeg 或者其他的开源库对 MP4 文件进行解码。这些开源库提供了一些 API,可以方便地将 MP4 文件解码为 YUV 格式的视频数据。例如,可以使用 FFmpeg 的 avcodec_decode_video2() 函数将 MP4 文件解码为 YUV 格式的视频数据。 2. 在解码过程中,需要将解码出来的视频数据保存到内存中。可以使用 C++ 的动态内存分配方式,例如 new 或者 malloc 函数来分配存储视频数据的内存。需要注意的是,内存的大小应该根据视频的分辨率、率和像素格式来确定。 3. 将解码出来的 YUV 格式的视频数据保存到文件中。可以使用 C++ 的文件操作函数,例如 fopen、fwrite 等函数将视频数据写入文件中。 代码示例: ```c++ #include <iostream> #include <fstream> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> using namespace std; // 输入文件名 const char* input_filename = "input.mp4"; // 输出文件名 const char* output_filename = "output.yuv"; int main(int argc, char* argv[]) { int ret; AVFormatContext* fmt_ctx = NULL; AVCodecContext* codec_ctx = NULL; AVCodec* codec = NULL; AVPacket pkt; AVFrame* frame = NULL; int video_stream_idx = -1; FILE* fp_out = NULL; int frame_count = 0; // 1. 打开输入文件 ret = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Could not open input file '%s'", input_filename); return ret; } // 2. 查找视频流 ret = avformat_find_stream_info(fmt_ctx, NULL); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Could not find stream information"); goto end; } for (int i = 0; i < fmt_ctx->nb_streams; i++) { AVStream* stream = fmt_ctx->streams[i]; if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_idx = i; break; } } if (video_stream_idx == -1) { av_log(NULL, AV_LOG_ERROR, "Could not find video stream"); ret = -1; goto end; } // 3. 打开视频解码器 codec_ctx = avcodec_alloc_context3(NULL); if (!codec_ctx) { av_log(NULL, AV_LOG_ERROR, "Could not allocate video codec context"); ret = AVERROR(ENOMEM); goto end; } ret = avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_stream_idx]->codecpar); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Could not copy codec parameters to codec context"); goto end; } codec = avcodec_find_decoder(codec_ctx->codec_id); if (!codec) { av_log(NULL, AV_LOG_ERROR, "Could not find decoder for codec ID %d", codec_ctx->codec_id); goto end; } ret = avcodec_open2(codec_ctx, codec, NULL); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Could not open codec"); goto end; } // 4. 分配解码内存 frame = av_frame_alloc(); if (!frame) { av_log(NULL, AV_LOG_ERROR, "Could not allocate frame"); ret = AVERROR(ENOMEM); goto end; } // 5. 打开输出文件 fp_out = fopen(output_filename, "wb+"); if (!fp_out) { av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", output_filename); ret = -1; goto end; } // 6. 解码视频 while (1) { ret = av_read_frame(fmt_ctx, &pkt); if (ret < 0) { break; } if (pkt.stream_index == video_stream_idx) { ret = avcodec_send_packet(codec_ctx, &pkt); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Error sending a packet for decoding"); break; } while (1) { ret = avcodec_receive_frame(codec_ctx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Error during decoding"); goto end; } if (frame_count++ % 25 == 0) { // 7. 将解码出来的 YUV 数据保存到文件中 for (int i = 0; i < codec_ctx->height; i++) { fwrite(frame->data[0] + i * frame->linesize[0], 1, codec_ctx->width, fp_out); } for (int i = 0; i < codec_ctx->height / 2; i++) { fwrite(frame->data[1] + i * frame->linesize[1], 1, codec_ctx->width / 2, fp_out); } for (int i = 0; i < codec_ctx->height / 2; i++) { fwrite(frame->data[2] + i * frame->linesize[2], 1, codec_ctx->width / 2, fp_out); } } } } av_packet_unref(&pkt); } end: avformat_close_input(&fmt_ctx); avcodec_free_context(&codec_ctx); av_frame_free(&frame); if (fp_out) { fclose(fp_out); } return ret; } ``` 这段代码使用 FFmpeg 库将 MP4 文件解码为 YUV 格式的视频数据,并将视频数据保存到文件中。需要注意的是,代码中只是将每隔 25 的视频数据保存到文件中,你可以根据需要调整保存视频数据的频率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值