热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ffmpeg学习日记5使用ffmpeg进行h264解码

ffmpeg学习日记5-使用ffmpeg进行h264解码文章目录首先解惑几个专业术语:解码步骤函数解释项目环境介绍编码中的报错释义报错1ubuntu安装libx264ubuntu下



ffmpeg学习日记5-使用ffmpeg进行h264解码


文章目录


  • 首先解惑几个专业术语:
  • 解码步骤
  • 函数解释
  • 项目环境介绍
  • 编码中的报错释义
    • 报错1
    • ubuntu安装libx264
    • ubuntu下将libx264编译进ffmpeg
    • 报错2

  • 安装新版本后的编译环境
  • 项目完整代码如下
  • 参考
  • 后记


当我们确定一个视频的编码格式是使用h264进行编码的,那么就可以进行对应的解码,将视频解码之后,解码数据才可以进行相应的渲染,加特效的操作,下面学习如何对视频进行解码。


首先解惑几个专业术语:
  • YUV数据
    YUV:视频像素格式 YUV数据:视频像素格式数据
  • H264
    H264:视频压缩数据格式

解码步骤
  1. 注册组件


  1. 初始化封装格式上下文


  1. 获取源文件属性参数值


  1. 查找编码器


  1. 打开视频解码器


  1. 进行解码


  1. 数据存储


  1. 释放解码器


函数解释

  • AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
    功能:分配一个AVCodecContext并将其字段设置为默认值,结果结构应该释放使用avcodec_free_context()
    参数:编解码器如果非null,分配私有数据并初始化给定编解码器的默认值。然后使用不同的编解码器调用avcodec_open2()是非法的。如果为NULL,那么特定于编解码器的默认值将不会被初始化,这可能会导致次优的默认设置(这主要对编码器来说很重要,例如libx264)。
    返回值:返回一个经过填充默认值的AVCodecContext机构,失败时为NULL
  • AVFrame *av_frame_alloc(void);
    功能:分配一个AVFrame并将其字段设置为默认值。结果结构必须使用av_frame_free()释放。
    返回值:一个AVFrame填充默认值或失败时为NULL。
    note:这只分配了AVFrame本身,而不是数据缓冲区。这些必须通过其他方式分配,例如通过av_frame_get_buffer()或手动分配。
  • int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
    int *got_picture_ptr,
    const AVPacket *avpkt);
    功能:解码一帧视频数据。输入一个压缩编码的结构体AVPacket,输出一个解码后的结构体AVFrame。

项目环境介绍

ffmpeg版本:

>ffmpeg -version
ffmpeg version n4.4-78-g031c0cb0b4-20210628 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 10-win32 (GCC) 20210408
configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-cOnfig=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --enable-shared --disable-static --disable-w32threads --enable-pthreads --enable-iconv --enable-libxml2 --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-lzma --enable-fontconfig --enable-libvorbis --enable-opencl --enable-libvmaf --enable-vulkan --enable-amf --enable-libaom --enable-avisynth --enable-libdav1d --enable-libdavs2 --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-libglslang --enable-libgme --enable-libass --enable-libbluray --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvpx --enable-libwebp --enable-lv2 --enable-libmfx --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --enable-libvidstab --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-ldflags=-pthread --extra-ldexeflags= --extra-libs=-lgomp --extra-version=20210628
libavutil 56. 70.100 / 56. 70.100
libavcodec 58.134.100 / 58.134.100
libavformat 58. 76.100 / 58. 76.100
libavdevice 58. 13.100 / 58. 13.100
libavfilter 7.110.100 / 7.110.100
libswscale 5. 9.100 / 5. 9.100
libswresample 3. 9.100 / 3. 9.100
libpostproc 55. 9.100 / 55. 9.100

qt版本:5.12.0


编码中的报错释义

报错1


  • avcodec_encode_video2 -22
    原因:没有编码器,安装libx264 ,这个是编码时的报错,解码报错应该也是一样的,
    参考:
  • avcodec_encode_video2 -22
    这个解决办法是安装libx264,要进行编译安装,在win10下我不熟悉,所以,将重新搭建一个编译环境,环境为:

$ cat /etc/issue
ubuntu:Ubuntu 20.04.2 LTS \n \l
qt:5.12.3

ffmpeg安装参考ffmpeg学习日记1-ffmpeg的基本介绍(相关概念理解,资料收集)中的安装ffmpeg段落。


ubuntu安装libx264

$ wget https://johnvansickle.com/ffmpeg/release-source/libx264-git.tar.xz
$ tar -xvf libx264-git.tar.xz
$ cd libx264-git/
$ sudo ./configure --enable-shared
$ sudo make -j4
$ sudo make install

参考:


  • ubuntu 下安装x264库

ubuntu下将libx264编译进ffmpeg

$ sudo ./configure --enable-shared --prefix=/usr/local/ffmpeg --enable-libx264 --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/lib --enable-gpl
$ sudo make -j4
$ sudo make install

参考:


  • linux 编译安装ffmpeg 与libx264的方法

编译完成后,运行项目,ret = avcodec_decode_video2(pCodecCtx,pFrame,&ret,&packet);语句未报错。


报错2


安装新版本后的编译环境

ffmpeg版本:

$ ffmpeg -version
ffmpeg version 4.1 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 9 (Ubuntu 9.3.0-17ubuntu1~20.04)
configuration: --enable-shared --prefix=/usr/local/ffmpeg --enable-libx264 --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/lib --enable-gpl
libavutil 56. 22.100 / 56. 22.100
libavcodec 58. 35.100 / 58. 35.100
libavformat 58. 20.100 / 58. 20.100
libavdevice 58. 5.100 / 58. 5.100
libavfilter 7. 40.101 / 7. 40.101
libswscale 5. 3.100 / 5. 3.100
libswresample 3. 3.100 / 3. 3.100
libpostproc 55. 3.100 / 55. 3.100

qt版本:5.12.2

Note:
在ffmpeg4.1版本中,去除了libavcodec/packet.h这个头文件。


项目完整代码如下

pro文件内容:

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += \
main.cpp
INCLUDEPATH += /usr/local/ffmpeg/include
LIBS += /usr/local/ffmpeg/lib/libavcodec.so \
/usr/local/ffmpeg/lib/libavdevice.so \
/usr/local/ffmpeg/lib/libavfilter.so \
/usr/local/ffmpeg/lib/libavformat.so \
/usr/local/ffmpeg/lib/libavutil.so \
/usr/local/ffmpeg/lib/libpostproc.so \
/usr/local/ffmpeg/lib/libswresample.so \
/usr/local/ffmpeg/lib/libswscale.so

main.cpp内容如下:

#include
#include
#include
using namespace std;
extern "C"{
#include
#include
#include "libavutil/avutil.h"
#include "libavformat/avformat.h"
//#include "libavcodec/packet.h"
#include "libavcodec/avcodec.h"
}
int main(int argc,char **argv)
{
cout <<"Hello World!" < //注册组件
avcodec_register_all();
AVCodecID codec_id = AV_CODEC_ID_H264;
AVCodec *pcodec = NULL;
AVCodecContext *pCodecCtx = NULL;
//查找编码器
pcodec = avcodec_find_decoder(codec_id);
if(!pcodec){
av_log(NULL,AV_LOG_ERROR,"no found decoder\n");
return 0;
}
//初始化封装格式上下文
pCodecCtx = avcodec_alloc_context3(pcodec);
if(!pCodecCtx){
av_log(NULL,AV_LOG_ERROR,"avcodec_alloc_context3 is failed\n");
return 0;
}
//初始化参数,下面的参数应该由具体的业务决定
pCodecCtx->time_base.num = 1;
pCodecCtx->frame_number = 1;
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
pCodecCtx->bit_rate = 0;
pCodecCtx->time_base.den = 29;
pCodecCtx->width = 544;
pCodecCtx->height = 960;
//打开视频解码器
if (avcodec_open2(pCodecCtx,pcodec,NULL) <0){
av_log(NULL,AV_LOG_ERROR,"avcodec_open2 is failed\n");
return 0;
}
//读取文件数据
char *buff = new char[1024*1024*4];
fstream fileio;
fileio.open("../jk.mp4",ios::binary | ios::in);
fileio.read(buff,1024*1024*4);
cout <<"read size:" < fileio.close();
//进行解码
int ret = 0;
AVFrame *pFrame = NULL;
pFrame = av_frame_alloc();
AVPacket packet;
av_init_packet(&packet);
ret = avcodec_decode_video2(pCodecCtx,pFrame,&ret,&packet);
cout <<"ret:" < if ((ret <0) && (ret != AVERROR(EAGAIN)) && (ret != AVERROR_EOF) ){
av_log(NULL,AV_LOG_ERROR,"avcodec_send_packet error\n");
return 0;
}
else {
cout <<"start" < int picSize = pCodecCtx->height * pCodecCtx->width;
int newSize = int(picSize * 1.5);
//申请内存
unsigned char *buf = new unsigned char[newSize];
//数据写入
int a = 0,i = 0;
for(i = 0;i height;i++){
memcpy(buf+a,pFrame->data[0] + i*pFrame->linesize[0],pCodecCtx->width );
a += pCodecCtx->width;
}
for (i = 0;i height/2;i++){
memcpy(buf+a,pFrame->data[1] + i*pFrame->linesize[1],pCodecCtx->width/2 );
a += pCodecCtx->width/2;
}
for (i = 0;i height/2;i++){
memcpy(buf+a,pFrame->data[2] + i*pFrame->linesize[2],pCodecCtx->width/2 );
a += pCodecCtx->width/2;
}
cout <<"data:" < }
return 0;
}

参考

  • ffmpeg视频的编码Encode—YUV编码为h264

  • FFmpeg实时解码H264

  • ffmpeg 源代码简单分析 : avcodec_decode_video2()

  • H264 编解码协议详解

  • ffmpeg实战教程(一)Mp4,mkv等格式解码为h264和yuv数据


后记

推荐阅读
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 类加载机制是Java虚拟机运行时的重要组成部分。本文深入解析了类加载过程的第二阶段,详细阐述了从类被加载到虚拟机内存开始,直至其从内存中卸载的整个生命周期。这一过程中,类经历了加载(Loading)、验证(Verification)等多个关键步骤。通过具体的实例和代码示例,本文探讨了每个阶段的具体操作和潜在问题,帮助读者全面理解类加载机制的内部运作。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 在使用 Qt 进行 YUV420 图像渲染时,由于 Qt 本身不支持直接绘制 YUV 数据,因此需要借助 QOpenGLWidget 和 OpenGL 技术来实现。通过继承 QOpenGLWidget 类并重写其绘图方法,可以利用 GPU 的高效渲染能力,实现高质量的 YUV420 图像显示。此外,这种方法还能显著提高图像处理的性能和流畅性。 ... [详细]
  • PHP预处理常量详解:如何定义与使用常量 ... [详细]
  • 使用Maven JAR插件将单个或多个文件及其依赖项合并为一个可引用的JAR包
    本文介绍了如何利用Maven中的maven-assembly-plugin插件将单个或多个Java文件及其依赖项打包成一个可引用的JAR文件。首先,需要创建一个新的Maven项目,并将待打包的Java文件复制到该项目中。通过配置maven-assembly-plugin,可以实现将所有文件及其依赖项合并为一个独立的JAR包,方便在其他项目中引用和使用。此外,该方法还支持自定义装配描述符,以满足不同场景下的需求。 ... [详细]
  • 在 Linux 环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用 pthreads 库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。 ... [详细]
  • Objective-C 中的委托模式详解与应用 ... [详细]
  • AIX编程挑战赛:AIX正方形问题的算法解析与Java代码实现
    在昨晚的阅读中,我注意到了CSDN博主西部阿呆-小草屋发表的一篇文章《AIX程序设计大赛——AIX正方形问题》。该文详细阐述了AIX正方形问题的背景,并提供了一种基于Java语言的解决方案。本文将深入解析这一算法的核心思想,并展示具体的Java代码实现,旨在为参赛者和编程爱好者提供有价值的参考。 ... [详细]
  • 2018年9月21日,Destoon官方发布了安全更新,修复了一个由用户“索马里的海贼”报告的前端GETShell漏洞。该漏洞存在于20180827版本的某CMS中,攻击者可以通过构造特定的HTTP请求,利用该漏洞在服务器上执行任意代码,从而获得对系统的控制权。此次更新建议所有用户尽快升级至最新版本,以确保系统的安全性。 ... [详细]
  • 如何在MySQL中选择合适的表空间以优化性能和管理效率
    在MySQL中,合理选择表空间对于提升表的管理和访问性能至关重要。表空间作为MySQL中用于组织和管理数据的一种机制,能够显著影响数据库的运行效率和维护便利性。通过科学地配置和使用表空间,可以优化存储结构,提高查询速度,简化数据管理流程,从而全面提升系统的整体性能。 ... [详细]
  • 在Ubuntu系统中配置Python环境变量是确保项目顺利运行的关键步骤。本文介绍了如何将Windows上的Django项目迁移到Ubuntu,并解决因虚拟环境导致的模块缺失问题。通过详细的操作指南,帮助读者正确配置虚拟环境,确保所有第三方库都能被正确识别和使用。此外,还提供了一些实用的技巧,如如何检查环境变量配置是否正确,以及如何在多个虚拟环境之间切换。 ... [详细]
  • 在腾讯云服务器上部署Nginx的详细指南中,首先需要确保安装必要的依赖包。如果这些依赖包已安装,可直接跳过此步骤。具体命令包括 `yum -y install gcc gcc-c++ wget net-tools pcre-devel zlib-devel`。接下来,本文将详细介绍如何下载、编译和配置Nginx,以确保其在腾讯云服务器上顺利运行。此外,还将提供一些优化建议,帮助用户提升Nginx的性能和安全性。 ... [详细]
  • 哈希表(Hash Table)是一种高效的查找算法,与传统的链表和树结构相比,其在查找过程中无需进行逐个元素的比较。本文将深入探讨哈希表的基本原理、应用场景以及优化策略,帮助读者全面理解其在实际开发中的优势和局限性。通过实例分析和代码示例,我们将展示如何有效利用哈希表提高数据处理效率,并解决常见的冲突问题。 ... [详细]
author-avatar
樱花落下的那天
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有