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 -= qtSOURCES += \main.cppINCLUDEPATH += /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 <iostream>
#include <string>
#include <fstream>using namespace std;extern "C"{
#include <stdio.h>
#include <stdlib.h>
#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!" << endl;//注册组件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.gcount() << endl;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:" << ret << endl;  //-22if ((ret < 0)  && (ret != AVERROR(EAGAIN)) && (ret != AVERROR_EOF) ){av_log(NULL,AV_LOG_ERROR,"avcodec_send_packet error\n");return 0;}else {cout << "start" << endl;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 < pCodecCtx->height;i++){memcpy(buf+a,pFrame->data[0] + i*pFrame->linesize[0],pCodecCtx->width );a += pCodecCtx->width;}for (i = 0;i < pCodecCtx->height/2;i++){memcpy(buf+a,pFrame->data[1] + i*pFrame->linesize[1],pCodecCtx->width/2 );a += pCodecCtx->width/2;}for (i = 0;i < pCodecCtx->height/2;i++){memcpy(buf+a,pFrame->data[2] + i*pFrame->linesize[2],pCodecCtx->width/2 );a += pCodecCtx->width/2;}cout << "data:" << buf << endl;}return 0;
}

参考

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

  • FFmpeg实时解码H264

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

  • H264 编解码协议详解

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

后记

ffmpeg学习日记5-使用ffmpeg进行h264解码相关推荐

  1. ffmpeg学习日记604-指令-将视频格式转为H264格式

    ffmpeg学习日记604-指令-将视频格式转为H264格式 在第四篇中,想要解码视频,缺没有弄清楚怎样的一个数据流,现在又明晰了一点,所谓的h264编解码,并不是直接将视频格式,通过h264编解码为 ...

  2. ffmpeg学习日记701-报错-co located POCs unavailable

    ffmpeg学习日记701-报错-co located POCs unavailable h264 co located POCs unavailable 出现该报错,是由于直接解析的帧是非关键帧,没 ...

  3. ffmpeg学习日记506-源码-av_image_copy()函数分析及功能

    ffmpeg学习日记506-源码-av_image_copy()函数分析及功能 实现文件 av_image_copy()实现在libavutil/imgutils.c中 函数原型 void av_im ...

  4. ffmpeg学习日记17-获取MP4视频流的帧率

    ffmpeg学习日记17-获取MP4视频流的帧率 参考各位大佬的文章,终于磕磕绊绊的理解,写出了获取MP4视频流的帧率等信息的代码 win10系统下运行 代码如下: getMp4FrameNum.pr ...

  5. ffmpeg学习日记612-指令-转换视频格式

    ffmpeg学习日记612-指令-转换视频格式 mkv转mp4 ffmpeg -i LostInTranslation.mkv -codec copy LostInTranslation.mp4 Li ...

  6. ffmpeg学习日记603-指令-获取视频分辨率

    ffmpeg学习日记603-指令-获取视频分辨率 ffmpeg:ffprobe获取视频分辨率,视频宽高,时长等元数据信息 ffprobe -select_streams v -show_entries ...

  7. ffmpeg学习日记605-指令-获取视频的总帧数

    ffmpeg学习日记605-指令-获取视频的总帧数 获取视频的总帧数 ffprobe.exe -v error -count_frames -select_streams v:0 -show_entr ...

  8. ffmpeg学习日记602-指令-转换视频的分辨率

    ffmpeg学习日记602-指令-转换视频的分辨率 指令如下 ffmpeg -i video_1920.mp4 -vf scale=640:360 video_640.mp4 -hide_banner

  9. 【FFmpeg学习笔记一】FFmpeg简介

    Fmpeg简介 一.FFmpeg简介 二.FFmpeg函数库 三.FFmpeg用例 四.相关链接 一.FFmpeg简介 FFmpeg是一款自由软件,核心功能就是音视频编解码,其中的"FF&q ...

  10. (FFMpeg学习笔记):FFmpeg下载、ffmpeg.exe与ffplay.exe的基本使用

    参考视频:https://www.bilibili.com/video/BV1gE411f7WT?t=3293 目录 背景 基本的DOS命令 FFmpeg命令行工具的获取 ffmpeg.exe的使用 ...

最新文章

  1. Nginx与PHP(FastCGI)的安装、配置、优化
  2. helm快速部署一个nginx应用并更改service类型为NodePort、自定义Chart的发布
  3. 如何查看自己的电脑是否支持EFI引导?我的是dell 15r-488 N5010 谢谢了!
  4. [vue] DOM渲染在哪个周期中就已经完成了?
  5. V210调整根分区大小
  6. Maven入门基础-环境篇
  7. 医学专业考计算机三级,2020年9月中国医科大学计算机等级考试报名通知
  8. java如何连接Oracle数据库问题
  9. poj 1185(状态压缩DP)
  10. JAVA继承与多态概述
  11. oracle中外键的使用方法,Oracle数据库中外键的相关操作整理
  12. mongodb mapredReduce 多个条件分组(group by)
  13. 模拟电路与数字电路基础之模拟信号与数字信号 学习笔记
  14. LayUI分页查询展示数据(SSH框架)
  15. input/output is not in graph tf.layers.conv2d在name命名时会自动在其后添加Conv2D
  16. 电脑常用快捷键的使用
  17. no identity-based policy allows the cloudformation:CreateStack action
  18. java-unrar-0.3.jar_java-unrar-0.3.jar解压
  19. 【Python自然语言处理】读书笔记:第五章:分类和标注词汇
  20. 百合股份上市被暂缓表决:自主品牌收入占比仅约三成,曾多次因安全问题被处罚

热门文章

  1. ssr 端口已被占用_解决 SSR for Windows 客户端烦人的 1080 端口已被占用
  2. 华为培训中华为数通HCIE考试流程-ielab
  3. editormd富文本编辑器
  4. 跟我学折纸计算机教案,折纸活动教案
  5. 《计算机操作系统》| 第一章 操作系统引论 知识梳理
  6. 中国接线端子行业研究与投资前景研究报告(2022版)
  7. 【C语言】使用Qt5学习C语言编写Hello World
  8. 11.2 RS232通信接口
  9. 手机投屏电视html,手机怎么投屏,怎么把手机里的电影投屏到电视上
  10. SQL 数据库 学习 033 视图