基于 FFMPEG 的跨平台视频播放器简明教程(三):视频解码

这篇具有很好参考价值的文章主要介绍了基于 FFMPEG 的跨平台视频播放器简明教程(三):视频解码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

系列文章目录

  1. 基于 FFmpeg 的跨平台视频播放器简明教程(一):FFMPEG + Conan 环境集成
  2. 基于 FFmpeg 的跨平台视频播放器简明教程(二):基础知识和解封装(demux)


前言

在前面章节 基于 FFMPEG 的跨平台视频播放器简明教程(二):基础知识和解封装(demux) 中我们引入了视频编解码的基础知识以及解封装的概念。

请记住我们的任务:使用 ffmpeg 解码视频,并将解码后的视频帧保存在本地(就像对视频截图一样)。今天,围绕这个任务让我们继续下一个知识点:视频解码。

本文参考文章来自 An ffmpeg and SDL Tutorial - Tutorial 01: Making Screencaps。这个系列对新手较为友好,但 2015 后就不再更新了,以至于文章中的 ffmpeg api 已经被弃用了。幸运的是,有人对该教程的代码进行重写,使用了较新的 api,你可以在 rambodrahmani/ffmpeg-video-player 找到这些代码。

本文的代码在 ffmpeg_video_player_tutorial-tutorial01。

使用 ffmpeg api 进行视频解码的步骤

概括来说,视频解码的步骤包括:

  1. 创建解码器
  2. 解封装,从视频流中读取一个 packet
  3. 将 packet 送给解码器,解码器进行解码
  4. 从解码器中,取回解码后的数据

创建解码器

在 ffmpeg 中与解码器相关的结构体有两个:AVCodec 和 AVCodecContext。

AVCodec结构体包含了编解码器的特定信息,如编解码器的类型、名称、支持的像素格式或音频样本格式等。你可以使用 avcodec_find_decoder 从 ffmpeg 支持的编解码器中找到你需要的那个。

AVCodec *avcodec_find_decoder(enum AVCodecID id);

avcodec_find_decoder 函数的主要目的是根据给定编解码器ID(AVCodecID)找到合适的解码器。在实现逻辑中,它对FFmpeg支持的所有编解码器进行迭代,并比较它们的AVCodecID与所需的AVCodecID。

如果发现有无法找到某个 id,有可能是因为你使用的 ffmpeg 做了裁剪,不支持这种类型的 codec,这时候你可以在代码中打印一下当前 ffmpeg 支持的 codec 信息:

const AVCodec *codec = NULL;
  void *i = 0;
  printf("List of supported codecs:\n");

  // Iterate over all codecs using av_codec_iterate
  // Note: use av_codec_next(codec) instead for older versions of FFmpeg
  while ((codec = av_codec_iterate(&i))) {
    printf("Codec name: %s, codec type: %s\n", codec->name,
           codec->type == AVMEDIA_TYPE_AUDIO      ? "Audio"
           : codec->type == AVMEDIA_TYPE_VIDEO    ? "Video"
           : codec->type == AVMEDIA_TYPE_SUBTITLE ? "Subtitle"
                                                  : "Other/Unknown");
  }

AVCodec 结构体仅仅是对某个编解码器的描述,要进行编解码还需要 AVCodecContext 参与。

在 FFmpeg 中,AVCodecContext 是一个结构体,它表示编解码器的上下文,主要负责存储与编解码器相关的配置信息和状态。AVCodecContext 的作用在于为音频、视频或字幕数据的编码和解码过程提供所需要的各种参数和数据。AVCodecContext 包含以下主要信息:

  1. 编解码器类型(音频、视频或字幕)
  2. 编解码器的 ID(用于标识特定的编解码器,例如 H.264,MP3 等)
  3. 时间基(用于计算时间戳)
  4. 帧率或采样率(视频或音频播放的速度)
  5. 比特率(编解码后的数据流的速率)
  6. 编码或解码期间使用的各种配置选项(如像素格式,音频通道数量,视频分辨率等)

要使用特定的 AVCodec 对象进行编解码,需要为其配置一个相应的 AVCodecContext,并设置相应的参数。然后使用 FFmpeg 提供的函数(如 avcodec_open2,avcodec_send_packet 等)对数据进行编解码。

因此,AVCodecContext 是连接原始数据、编解码器(AVCodec)和输出数据之间的桥梁。它帮助用户在输入和输出之间传递数据,并提供编解码过程所需的参数。

在代码中,使用 avcodec_alloc_context3 创建一个 AVCodecContext

pCodecCtx = avcodec_alloc_context3(pCodec); 

接着,需要填充 AVCodecContext 中各种信息,一种简便的方式是使用 avcodec_parameters_to_context

avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStream]->codecpar);

最后一步,使用 avcodec_open2 打开编解码器并与 AVCodecContext 相关联。

avcodec_open2(pCodecCtx, pCodec, NULL);

解封装,读取 packet

关于解封装我们在 基于 FFMPEG 的跨平台视频播放器简明教程(二):基础知识和解封装(demux) 已经做了详细的介绍。

从文件中读取一个 packet 非常简单,代码如下:

AVPacket * pPacket = av_packet_alloc(); 
av_read_frame(pFormatCtx, pPacket); // 从 AVFormatContext 中读取一个 packet
if(pPacket->stream_index == videoStream) // 只处理视频流
{
	// do something
} 
  1. av_packet_alloc 用于申请一个 AVPacket
  2. av_read_frame 从 AVFormatContext 中读取一个 packet
  3. 判断当前 packet 是否是视频数据(或者其他你想要的数据),接着进行处理

将 packet 送给解码器,解码器进行解码

这一步非常简单,调用 avcodec_send_packet 即可。avcodec_send_packet函数的主要作用如下:

  1. 将输入的压缩数据包传递给解码器进行解码。
  2. 在数据发送完毕时(例如,文件结束或流结束),传递NULL数据包以通知解码器将剩余数据刷新。

avcodec_send_packet 函数的返回值是值得注意的,用于表示操作的结果。以下是可能的返回值及其含义:

  • 0:操作成功。这意味着输入的压缩数据包已成功传递给解码器。

  • AVERROR(EAGAIN):当前解码器的状态不允许接收更多的数据包。这通常意味着解码器内部缓冲区已满,需要先调用avcodec_receive_frame()函数接收解码帧才能继续发送数据包。

  • AVERROR_EOF:解码器已经被刷新并且不再接受数据包。这意味着文件或流已结束,并且解码器已经清空。

  • AVERROR(EINVAL):提供的AVCodecContext或AVPacket无效,例如AVCodecContext为NULL。也可能意味着解码器没有被正确打开,或者在编码器AVCodecContext上调用了avcodec_send_packet。

  • AVERROR(ENOMEM):解码器内部缓冲区分配失败,内存不足。

  • 其他负数:其他库错误或解码器实现特定的错误代码,具体的错误代码可以通过 av_err2str 函数将错误码转为字符串进行输出。

从解码器中,取回解码后的数据

这一步也非常简单,使用 avcodec_receive_frame 从 codec 中取回解码后的数据。avcodec_receive_frame 函数的主要作用如下:

  1. 尝试从解码器获得已解码的帧(例如,解码后的视频或音频帧)。
  2. 提供对解码器内部缓冲区和状态管理的抽象,使得调用者不需要直接处理内部缓冲区和状态。
  3. 在解码器已经处理完所有输入数据包且内部缓冲区已空时,返回AVERROR_EOF,从而告知调用者解码过程已完成。
  4. 如果解码器需要更多的输入数据包才能生成解码帧,则返回AVERROR(EAGAIN),告知调用者继续发送数据包。

avcodec_send_packetavcodec_receive_frame 一般是成配对使用的,但是你看代码通常这部分代码会夹杂了一些 while/for 循环,这是为啥?这是因为 packet 与 frame 的生成速度不一定是一对一的:avcodec_send_packet 发送了一个 packet 之后,avcodec_receive_frame 可能没有产生,也可能产出多帧。因此你需要用一个 for/while 循环来处理。

while (ret >= 0) {
  ret = avcodec_receive_frame(pCodecCtx, pFrame); 

  if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
    // EOF exit loop
    break;
  } else if (ret < 0) {
    // could not decode packet
    printf("Error while decoding.\n");

    // exit with error
    return -1;
  }
}

总结

本文说明了使用 ffmpeg api 进行视频解码的流程,步骤顺序为:

  1. 创建解码器
  2. 解封装,从视频流中读取一个 packet
  3. 将 packet 送给解码器,解码器进行解码
  4. 从解码器中,取回解码后的数据

整个过程中,最为关键的部分是使用 avcodec_send_packet 和 avcodec_receive_frame 进行解码操作。理解这两个 api 是理解视频解码的关键。文章来源地址https://www.toymoban.com/news/detail-482580.html

参考

  • ffmpeg_video_player_tutorial-tutorial01
  • An ffmpeg and SDL Tutorial - Tutorial 01: Making Screencaps

到了这里,关于基于 FFMPEG 的跨平台视频播放器简明教程(三):视频解码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于 FFMPEG 的跨平台视频播放器简明教程(二):基础知识和解封装(demux)

    基于 FFmpeg 的跨平台视频播放器简明教程(一):FFMPEG + Conan 环境集成 前面一章中我们介绍了如何使用 conan 和 cmake 搭建 ffmpeg 运行环境,你做的还顺利吗?如果遇到任何问题,请在进行评论,我看到都会回复的。 从本章开始,将正式开始我们的 ffmpeg 播放器学习之旅。接下去

    2024年02月08日
    浏览(74)
  • QtAV:基于Qt和FFmpeg的跨平台高性能音视频播放框架

    目录 一.简介 1.特性 2.支持的平台 3.简单易用的接口 二.编译 1.下载依赖包 2.开始编译 2.1克隆 2.2修改配置文件 2.3编译 三.试用 官网地址:http://www.qtav.org/ Github地址:https://github.com/wang-bin/QtAV ●支持大部分播放功能 ●播放、暂停、播放速度、快进快退、字幕、音量、声道、音

    2024年01月22日
    浏览(46)
  • 开源的跨平台的音视频处理工具FFmpeg

    FFmpeg是一个开源的跨平台的音视频处理工具,可以对音频、视频进行转码、裁剪、调节音量、添加水印等操作。 广泛的格式支持。 FFmpeg能够解码、编码、转码、复用、分离、流式传输、过滤和播放几乎人类和机器所创造的任何内容。它支持最古老且晦涩难懂的格式,也支持

    2024年02月15日
    浏览(36)
  • FFmpeg——开源的开源的跨平台音视频处理框架简介

    引言:         FFmpeg是一个开源的跨平台音视频处理框架,可以处理多种音视频格式。它由Fabrice Bellard于2000年创建,最初是一个只包括解码器的项目。后来,很多开发者参与其中,为FFmpeg增加了多种新的功能,例如编码器、过滤器、muxer、demuxer等等,使它成为了一个完整

    2024年03月23日
    浏览(41)
  • 基于FFmpeg的视频播放器之三:拉取rtsp流

    拉取网络流和打开本地文件流程差不多,详见:基于FFmpeg的视频播放器之二:解复用,下面是不同地方。 方法有很多,最方便的应该是用VLC串流了,具体步骤如下:https://blog.csdn.net/m0_61353061/article/details/120388230 当然也可以使用live555作为rtsp服务器,可参考:https://blog.csdn.net

    2023年04月25日
    浏览(29)
  • 音视频项目—基于FFmpeg和SDL的音视频播放器解析(三)

    介绍 在本系列,我打算花大篇幅讲解我的 gitee 项目音视频播放器,在这个项目,您可以学到音视频解封装,解码,SDL渲染相关的知识。您对源代码感兴趣的话,请查看基于FFmpeg和SDL的音视频播放器 如果您不理解本文,可参考我的前一篇文章音视频项目—基于FFmpeg和SDL的音视

    2024年02月05日
    浏览(43)
  • 音视频项目—基于FFmpeg和SDL的音视频播放器解析(二十一)

    介绍 在本系列,我打算花大篇幅讲解我的 gitee 项目音视频播放器,在这个项目,您可以学到音视频解封装,解码,SDL渲染相关的知识。您对源代码感兴趣的话,请查看基于FFmpeg和SDL的音视频播放器 如果您不理解本文,可参考我的前一篇文章音视频项目—基于FFmpeg和SDL的音视

    2024年02月02日
    浏览(48)
  • QT软件开发-基于FFMPEG设计视频播放器-软解图像(一)

    QT软件开发-基于FFMPEG设计视频播放器-CPU软解视频(一) https://xiaolong.blog.csdn.net/article/details/126832537 QT软件开发-基于FFMPEG设计视频播放器-GPU硬解视频(二) https://xiaolong.blog.csdn.net/article/details/126833434 QT软件开发-基于FFMPEG设计视频播放器-解码音频(三) https://xiaolong.blog.csdn.

    2023年04月08日
    浏览(30)
  • ffmpeg跨平台arm编译-ubuntu

    32位系统: 64位系统: 关键选项: –arch=arm:指定ARM平台 –target-os=linux:指定Linux系统 –enable-cross-compile :指定交叉编译 –cross-prefix=arm-linux-gnueabihf-:指定交叉编译链 如果是64位系统: –arch=aarch64:指定ARM平台 –cross-prefix=aarch64-linux-gnu-:指定交叉编译链

    2024年02月08日
    浏览(37)
  • 论文精讲 | 基于昇思MindSpore打造首个深度学习开源视频压缩算法库OpenDMC,支持跨平台和多种评价指标

    论文标题 OpenDMC: An Open-Source Library and Performance Evaluation for Deep-learning-based Multi-frame Compression 论文来源 ACM MultiMedia 论文链接 https://www.acmmm2023.org/open-source-program/ 代码链接 https://openi.pcl.ac.cn/OpenDMC/OpenDMC 昇思MindSpore作为开源的AI框架,为产学研和开发人员带来端边云全场景协同、

    2024年02月02日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包