diario de aprendizaje ffmpeg 5 - decodificación h264 usando ffmpeg
Directorio de artículos
- Primero aclare algunos términos técnicos:
- pasos de decodificación
- explicación de la función
- Introducción al entorno del proyecto
- Interpretación de errores en la codificación
- El entorno de compilación después de instalar la nueva versión
- El código completo del proyecto es el siguiente
- referencia
- posdata
Cuando determinamos que el formato de codificación de un video está codificado usando h264, entonces se puede realizar la decodificación correspondiente. Después de decodificar el video, los datos decodificados se pueden representar en consecuencia y se pueden agregar efectos especiales. Aprendamos cómo decodificar el video.
Primero aclare algunos términos técnicos:
- Datos YUV
YUV: formato de píxel de video Datos YUV: datos de formato de píxel de video - H264
H264: formato de datos de compresión de video
pasos de decodificación
- registrar componente
- Inicializar el contexto de formato de encapsulación
- Obtener el valor del parámetro del atributo del archivo de origen
- encontrar codificador
- códec de vídeo abierto
- decodificar
- almacenamiento de datos
- liberar códec
explicación de la función
- AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
Función: asigne un AVCodecContext y configure sus campos a los valores predeterminados, la estructura resultante debe liberarse Use el
parámetro avcodec_free_context(): códec Si no es nulo, asigne datos privados e inicialice el códec dado el valor predeterminado para . Entonces llamar avcodec_open2() con un códec diferente es ilegal. Si es NULL, los valores predeterminados específicos del códec no se inicializarán, lo que puede conducir a valores predeterminados subóptimos (esto es principalmente importante para los codificadores, como libx264).
Valor devuelto: Devuelve un mecanismo AVCodecContext lleno de valores predeterminados, o NULL en caso de falla - AVFrame *av_frame_alloc(void);
Función: Asignar un AVFrame y establecer sus campos a los valores predeterminados. La estructura resultante debe liberarse usando av_frame_free().
Valor de retorno: un AVFrame lleno de valores predeterminados o NULL en caso de falla.
Nota: Esto solo asigna el AVFrame en sí, no el búfer de datos. Estos deben asignarse por otros medios, como a través de av_frame_get_buffer() o manualmente. - int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
const AVPacket *avpkt);
Función: decodifica un cuadro de datos de video. Ingrese una estructura comprimida y codificada AVPacket y emita una estructura decodificada AVFrame.
Introducción al entorno del proyecto
versión 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 versión: 5.12.0
Interpretación de errores en la codificación
error 1
- avcodec_encode_video2 -22
razón: no hay codificador, instale libx264, este es un error al codificar, el error debería ser el mismo al decodificar,
consulte:
La solución de avcodec_encode_video2 -22 es instalar libx264. Para compilar e instalar, no estoy familiarizado con win10, así que reconstruiré un entorno de compilación. El entorno es:
$ cat /etc/issue
ubuntu:Ubuntu 20.04.2 LTS \n \l
qt:5.12.3
Para la instalación de ffmpeg, consulte los párrafos en el diario de aprendizaje de ffmpeg 1: introducción básica de ffmpeg (comprensión de conceptos relacionados, recopilación de datos)安装ffmpeg
.
ubuntu instalar 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
referencia:
Compile libx264 en ffmpeg bajo ubuntu
$ 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
referencia:
Una vez completada la compilación, ejecute el proyecto y ret = avcodec_decode_video2(pCodecCtx,pFrame,&ret,&packet);
la declaración no informa de un error.
error 2
El entorno de compilación después de instalar la nueva versión
versión 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 versión: 5.12.2
Nota:
En la versión ffmpeg4.1, se elimina el archivo de encabezado libavcodec/packet.h.
El código completo del proyecto es el siguiente
contenido del archivo profesional:
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
El contenido de main.cpp es el siguiente:
#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;
}
referencia
-
Codificación de video ffmpeg Codificación: la codificación YUV es h264
-
Análisis simple del código fuente de ffmpeg: avcodec_decode_video2()
-
Tutorial práctico de ffmpeg (1) Mp4, mkv y otros formatos se decodifican en datos h264 y yuv