美文网首页
ffmpeg将MP4文件解码为yuv数据

ffmpeg将MP4文件解码为yuv数据

作者: 3c1b8ae8346c | 来源:发表于2021-08-03 10:17 被阅读0次

温习ffmpeg的使用

1. 主要函数的调用流程

av_register_all 注册编解码器

avformat_alloc_context 初始化封装格式上下文, 用于mp4等视频格式的封装和解封装

avformat_open_input 解封装一个视频文件

avcodec_find_decoder 查找视频流解码器

av_read_frame 读取视频流的h264帧数据

avcodec_send_packet 将h264帧数据发送给解码器

avcodec_receive_frame 从解码器中读出解码后的yuv数据

2. 主要步骤

  1. 解封装视频文件 需要用到avformat开头的函数

  2. 在视频文件中找到视频流的解码器并且打开解码器

  3. 循环从视频文件中读取h264帧数据交给解码器解码,并且从解码器中读取解码后的yuv数据,最后写入yuv.data文件中

  4. 各种关闭

3.详细代码


void decode() {
    char *path = "d:/mvresult.mp4";

    av_register_all();//注册编解码器
    AVFormatContext *avformat_context = avformat_alloc_context(); //初始化封装格式上下文
    avformat_open_input(&avformat_context, path, NULL, NULL);    //打开视频文件
    int videoStream = -1;
    for(int i = 0; i < avformat_context->nb_streams; i++) {//查找视频流
        if (avformat_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStream = i;
        }
    }

    if (videoStream == -1) {
        return;
    }

    AVCodecContext *avcodec_context = avformat_context->streams[videoStream]->codec;
    AVCodec *codec = avcodec_find_decoder(avcodec_context->codec_id);//查找视频流的解码器
    if (avcodec_open2(avcodec_context, codec, nullptr) < 0) {//打开解码器
        return;
    }

    AVFrame *frame = av_frame_alloc();
    AVPacket *packet = av_packet_alloc();
    av_init_packet(packet);

    FILE* pFile = fopen("d:/yuv420.data", "w");

    SwsContext* sws_context = sws_getContext(avcodec_context->width, avcodec_context->height,
                    avcodec_context->pix_fmt, avcodec_context->width, avcodec_context->height,
                    AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

    AVFrame *pFrameYUV = av_frame_alloc();

    unsigned char * out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, avcodec_context->width, avcodec_context->height));
    avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, avcodec_context->width, avcodec_context->height);

    int index = 0;

    while(true) {
        av_read_frame(avformat_context, packet);//读取文件中的h264帧
        if (packet->stream_index == videoStream) {
            int ret = avcodec_send_packet(avcodec_context, packet);//将h264帧发送到解码器
            if (ret < 0) {
                break;
            }
            while (true) {
                int ret = avcodec_receive_frame(avcodec_context, frame);//从解码器获取帧
                if (ret) {
                    break;
                }
                sws_scale(sws_context,(uint8_t const * const *) frame->data,
                                                        frame->linesize, 0, avcodec_context->height, pFrameYUV->data,
                                                        pFrameYUV->linesize);//将帧数据转为yuv420p

                fwrite(pFrameYUV->data[0], sizeof( uint8_t ), avcodec_context->width * avcodec_context->height, pFile);//将y数据写入文件中
                fwrite(pFrameYUV->data[1], sizeof( uint8_t ), avcodec_context->width * avcodec_context->height / 4, pFile);//将u数据写入文件中
                fwrite(pFrameYUV->data[2], sizeof( uint8_t ), avcodec_context->width * avcodec_context->height / 4, pFile);//将v数据写入文件中
            }
        }
    }
    sws_freeContext(sws_context);
    av_frame_free(&frame);
    av_packet_free(&packet);
    avcodec_close(avcodec_context);
    avformat_close_input(&avformat_context);
    fclose(pFile);

}



相关文章

网友评论

      本文标题:ffmpeg将MP4文件解码为yuv数据

      本文链接:https://www.haomeiwen.com/subject/vcuevltx.html