其他分享
首页 > 其他分享> > ffmpeg学习日记5-使用ffmpeg进行h264解码

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

作者:互联网

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

文章目录


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

首先解惑几个专业术语:

解码步骤

  1. 注册组件
  1. 初始化封装格式上下文
  1. 获取源文件属性参数值
  1. 查找编码器
  1. 打开视频解码器
  1. 进行解码
  1. 数据存储
  1. 释放解码器

函数解释

项目环境介绍

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

$ 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下将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

参考:

编译完成后,运行项目,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 <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;  //-22

    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" << 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;
}

参考

后记

标签:enable,pCodecCtx,ffmpeg,h264,解码,--,usr,local
来源: https://blog.csdn.net/bootleader/article/details/122868620