首页 C/C++ 正文
  • 本文约2254字,阅读需11分钟
  • 66
  • 0

FFmpeg解码播放视频原理

摘要

一概念 FFmpeg是一个强大的多媒体处理工具,广泛应用于视频录制、转换和流媒体播放等领域。在本文中,我们将讨论如何使用FFmpeg库API来播放视频文件,详细介绍播放流程、API使用以及代码示例。 二 FFmpeg视频解码播放流程 2.1、初始化FFmpeg库: 包括注册所有的文件格式和编解码器。 2.2、打开视频文件: 打开视频文件并读取文件头信息获取流...

一概念

FFmpeg是一个强大的多媒体处理工具,广泛应用于视频录制、转换和流媒体播放等领域。在本文中,我们将讨论如何使用FFmpeg库API来播放视频文件,详细介绍播放流程、API使用以及代码示例。

FFmpeg解码播放视频原理

二 FFmpeg视频解码播放流程

2.1、初始化FFmpeg库:

包括注册所有的文件格式和编解码器。

2.2、打开视频文件:

打开视频文件并读取文件头信息获取流信息。

2.3、查找视频流:

在文件的多个流中找到视频流的位置。

2.4、解码视频流:

使用对应的解码器解码视频流。

2.5、读取帧数据:

从视频流中读取原始的帧数据。

2.6、转换和渲染:

将原始帧数据转换为适合输出设备的格式(如:YUV转RGB),并渲染到屏幕上。

三 FFmpeg视频播放流程

FFmpeg解码播放视频原理

3.1、解封装(Demuxing):

将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。封装格式种类很多,例如MP4,MKV,RMVB,TS,FLV,AVI等等,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。例如,FLV格式的数据,经过解封装操作后,输出H.264编码的视频码流和AAC编码的音频码流。

3.2、解码(Decode):

将视频/音频压缩编码数据,解码成为非压缩的视频/音频原始数据。音频的压缩编码标准包含AAC,MP3等,视频的压缩编码标准则包含H.264,MPEG2等。解码是整个系统中最重要也是最复杂的一个环节。通过解码,压缩编码的视频数据输出成为非压缩的颜色数据,例如YUV、RGB等等;压缩编码的音频数据输出成为非压缩的音频抽样数据,例如PCM数据。

3.3、音视频同步:

根据解封装模块处理过程中获取到的参数信息,同步解码出来的音频和视频数据,并将音视频频数据送至系统的显卡和声卡播放出来(Render)。

3.4、FFMPEG音视频解码

通过上面对媒体文件播放步骤了解,在解码多媒体文件的时候需要经过两个步骤,即解封装(Demuxing)和解码(Decode)。下面就来看一下FFMPEG解码媒体文件的时候是怎样做这两个步骤的。

FFmpeg解码播放视频原理

四 FFmpeg代码示例

4.1、 初始化FFmpeg库


#include <libavformat/avformat.h>

// 初始化FFmpeg并注册所有编解码器和格式
av_register_all();

4.2、 打开视频文件

AVFormatContext *formatContext = NULL;

// 分配AVIOContext
AVIOContext* avioContext = avio_alloc_context(av_malloc(1024*1024), 1024*1024, 0, fopen(argv[1], "rb"), ReadPacket, NULL, NULL);

// 关联AVIOContext
formatContext = avformat_alloc_context();
formatContext->pb = avioContext;

if (avformat_open_input(&formatContext, NULL, NULL, NULL) != 0) {
    printf("无法打开输入文件\n");
    return -1;
}

4.3、 查找视频流

if (avformat_find_stream_info(formatContext, NULL) < 0) {
    printf("无法找到流信息\n");
    return -1;
}
 // 查找视频流
int videoStreamIndex = av_find_best_stream(formatContext, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);

if (videoStreamIndex == -1) {
    printf("未找到视频流\n");
    return -1;
}

4.4、打开编解码器

// 获取视频解码器
AVCodecParameters *codecParameters = formatContext->streams[videoStreamIndex]->codecpar;
AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id);
printf("codecParameters->codec_id = %d \n" , codecParameters->codec_id);
AVCodecContext *codecContext = avcodec_alloc_context3(codec);

if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) {
    printf("无法创建解码器上下文\n");
    return -1;
}

if (avcodec_open2(codecContext, codec, NULL) < 0) {
    printf("无法打开解码器\n");
    return -1;
}

4.5、 解码视频流

 // 读取并解码视频帧
while (av_read_frame(formatContext, &packet) >= 0) {
    if (packet.stream_index == videoStreamIndex) {
        // 发送数据到解码器
        printf("packet.size:%d \n" , packet.size);
        if (avcodec_send_packet(codecContext, &packet) != 0) {
            printf("发送数据到解码器失败\n");
            break;
        }

        // 接收解码后的帧数据
        while (avcodec_receive_frame(codecContext, frame) == 0) {
            // 格式转换
            yuv420p_to_yuyv(frame, yuyv_buffer, codecContext->width, codecContext->height);
            yuyv_to_dp550yuyv(yuyv_buffer, cvtdest, codecContext->width, codecContext->height, codecContext->width * 2, line_width);
            memcpy(fbp, cvtdest, bufferSize);               
        }
        frameCount++;
        gettimeofday(&end, NULL);
        double elapsedTime = (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000000.0;
        printf("Time taken to decode one frame: %.6f seconds\n", elapsedTime);
        gettimeofday(&start, NULL);
    }

    // 释放解码包资源
    av_packet_unref(&packet);
}

4.6、释放资源


av_frame_free(&frame);
avcodec_close(codecContext);
avformat_close_input(&formatContext);
munmap(fbp, bufferSize);
close(fbfd);
free(cvtdest);

五 总结

利用FFmpeg播放视频需要理解视频播放的基本流程,包括初始化FFmpeg, 打开视频文件, 查找视频流, 解码视频流, 以及转换和渲染视频帧。

FFmpeg解码播放视频原理

标签:FFmpeg

扫描二维码,在手机上阅读
    评论