FFmpeg is a very powerful set of video audio processing libraries, however, the powerful features are generally unavoidable complex implementations, or more realistically, the "trouble" of the deployment and use of the process
About "ffmpeg How to deploy" this is put in another article, the following into the topic:
Both the Encoding encoder module and the decoding decoder module have init initialization method and resource free method
The Init initialization method is mainly for the initialization of the codec necessary for FFmpeg and the parameter configuration of some function methods, while the free resource release method is necessary to recycle it accordingly.
Implementation and detail analysis of the Encoder module
#include <stdio.h>
#include <string.h>
#include <math.h>
The following are the necessary ffmpeg libraries
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channellayout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
Log method used after porting Android platform
#define LOGTAG "Android-ffmpeg-tutorial01"
#define Logi (...)androidlogprint (4, logTAG, VAARGS);
#define LOGE (...)androidlogprint (6, logTAG, VAARGS);
Macros define some fixed parameters
#define Dcodeformat AVCODECIdH264???//Encoding format, AVCODECIDH264 for FFmpeg code
#define PIXFMT AVPIXfmt_yuv420p????????????? Frame pixel format
#define DWIDTH 640??????????????????????????????????????????? ? Video width, original video and encoded width unchanged
#define DHEIGHT 480??????????????????????????????????????????? Video height, original video and height unchanged after encoding
#define Bitrate 400000
#define PACKETFRAMES 4??????????????????????????????????? I-frame and P-frame 1:3, the encoded packet, an I-frame followed by three P-frames? Ipppipppip .....
#define Framerate???????????????????????????????????????? Frame rate, this is 25fps.
Define some global variables
unsigned long long curpts = 0;??????????????????????????????????? Record the number of frames and set pts,pts for each frame keep incrementing, there are several statements on the PTS web but I don't know much about it.
int ErrorS = 0, ngot = 0; More than 0 means error?? Errors temporarily useless, ngot used to get "whether to get a code packet" tag
Avcodec *codec;??????????????????????????????????????????????????????? Encoder device
Avcodeccontext *cotx = NULL;????????????????????????????????? The encoder context, the main parameter setting, determines the operation of the encoder
Avframe *pframe;????????????????????????????????????????????????????? Frame, fill in the data to be encoded and then give it to the coding method for processing
Avpacket PKT;????????????????????????????????????????????????????????????? Package, the original frame encoding gets packet, storing the data obtained by the encoding
Encoder Environment Initialization
static void InitEncoder () {
int I, j, K;
curpts = 0;
AvcodecInit ();
AvcodecRegisterAll ();????????????????????????????????????????????????? Register all codecs and call the first step of Ffmpegapi
codec = AvcodecFindEncoder (Dcodeformat);???? Find and get a specific encoder, here is the H264 encoder
if (!CODEC) {//Cannot find the target encoder, exit
ErrorS = 1;
Logi ("Codec not found\n");
printf ("Codec not found\n");
Exit (1);
}
Cotx = AvcodecAllocCONTEXT3 (codec);??????????????????????? The context is understood as a parameter setting based on the encoder allocation context
if (!cotx) {//Cannot assign context, exit
ErrorS = 1;
Logi ("Could not allocate video codec context\n");
printf ("Could not allocate video codec context\n");
Exit (1);
}
Cotx->bitRate = bitrate,??????????????????????????????????????????????????????????????????????//Set bit rate
Cotx->width = Dwidth;
Cotx->height = Dheight;
Cotx->timeBase = (avrational) {1, framerate};???????????????????????????????? Here timebase.num = 1, timeBase.dem = 25
Cotx->gopsize = packetframes;??????????????????????????????????????????????????????//See macros define the notes there
Cotx->maxBframes = 0;???????????????????????????????????????????????????????????????????????//maximum number of B frames?! You do not want B-frames at this moment.
Cotx->pixFMT = pixfmt;???????????????????????????????????????????????????????????????????????? Frame pixel format
AVoptset (Cotx->priv_data, "preset", "slow", 0);???????????????????????????????????? Unknown origin. Declaration Header file is unknown
if (Avcodecopen2 (Cotx, codec, NULL) < 0) {?????????????????????????????????????????//Open encoder with "context" configured parameters, fail to exit
Logi ("Could not open codec\n");
printf ("Could not open codec\n");
Exit (1);
}
pframe = avframealloc ();?????????????????????????????????????????????????????????????????????//assigning frames
if (!pframe) {
Logi ("Could not allocate video frame\n");
printf ("Could not allocate video frame\n");
Exit (1);
}
Set the format of frame
Pframe->format = Cotx->pixfmt;????????????????????????????????????????????????????????????? Specify the frame pixel format
Pframe->width = cotx->width;?????????????????????????????????????????????????????????????????? Specify width height
Pframe->height = cotx->height;
The Last para Unknown
ErrorS = avImageAlloc (Pframe->data, pframe->linesize,?????????????????????//allocation according to width height and frame format, Mount image resource buffer for frame
Cotx->width, Cotx->height, cotx->pix_fmt, +);????????????????????????????????????? pframe->data[0,1,2,...] as buff pointer
if (ErrorS < 0) {????????????????????????????????????????????????????????????????????????????????????//pframe- >linesize[0,1,2,...] Byte number of a row (width) pixel in this format
Logi ("Could not allocate raw picture buffer\n");??????????????????????????????? Take YV12 's 640x480 frame as an example
printf ("Could not allocate raw picture buffer\n");?????????????????????????????????? PFRAME->DATA[0] Store y information, pframe->linesize[0] The original frame represents a row of pixels
Exit (1);????????????????????????????????????????????????????????????????????????????????????????????????? The number of bytes required for Y, here is 640
}??????????????????????????????????????????????????????????????????????????????????????????????????????????? PFRAME->DATA[1] and pframe->data[2] are vu information, respectively, and Pframe->linesize[1]
return;?????????????????????????????????????????????????????????????????????????????????????????????????? PFRAME->LINESIZE[2] is 320
}
Freeing resources
static void freeencoder () {
AVfreepacket (&PKT);?????????????????????????????????????????????????????????????????????????????/ /Release packet mount Buff,frame and packet can be said to correspond to "raw" and "encoded" resources respectively
AvcodecClose (cotx);????????????????????????????????????????????????????????????????????????????? Close "Context" and encoder
AVfree (cotx);????????????????????????????????????????????????????????????????????????????????????????//release " Context "Resource
AVfreep (&pframe->data[0]);????????????????????????????????????????????????????????????????? Free frame image Frames Buff
AVframefree (&pframe);???????????????????????????????????????????????????????????????????????? Releasing image Frames
}
/*
* For YV12 frame, h264 only
* Be sure the encoder have been initialized
*/
static int PacketFrameEncoder (const char *rawframes, int bytesize) {
Av FreePacket (&PKT);??????????????????????????????????????????????????????????????????????????????? Release packet buff, i.e. Pkt.data, where pkt is a struct, pkt.size is size
AvInitPacket (&PKT);????????????????????????????????????????????????????????????????????????????????? Initialize Packet
Pkt.data = NULL;??????????????????????????????????????????????????????????????????????????????????? Packet encoding is used to load encoded data, so data is set to null, length is 0
pkt.size = 0;
if (rawframes = = NULL) {
ErrorS = AvcodecencodeVideo2 (Cotx, &pkt, NULL, &ngot);
} else {
Y????????????????????????????????????????????????????????????????????????????????????????????????????????? According to the original resource format, the data to be encoded in the frame, where the original format is YV12
memcpy (Pframe->data[0], rawframes, (int) (Cotx->height * cotx->width));
Cr, Cb
memcpy (pframe->data[1], rawframes + (int) (Cotx->height * cotx->width), (int) (Cotx->height * cotx->width /4));
memcpy (pframe->data[2], rawframes + (int) (Cotx->height * cotx->width * 1.25), (int) (Cotx->height * cotx-> WIDTH/4));
pframe->pts = ++curpts;????????????????????????????????????????????????????????????????????????? To set pts for each frame, the use mechanism for timestamps is unclear, but should be Shinto
ErrorS = Avcodec encode video2 (Cotx, &pkt, Pframe, &ngot),??????????????????//encoded with the specified encoder and original frame, The encoded frame is packaged into the pkt,ngot and brought back to the
}??????????????????????????????????????????????????????????????????????????????????????????????????? ??????????? Whether to generate package information, sometimes a frame is split into multiple packages, sometimes multiple frames are hit a packet, so you need
If (ErrorS < 0) {????????????????????????????????//determine if the encoding process is an error????????????????//Determine if there is a packet generation after the original frame of the input,
// Logi ("Error encoding frame\n");????????????????????????????????????????????????????????? Sometimes you can enter multiple frames consecutively in order to encode the package, after all, like h264 this encoding, need to target
printf ("Error encoding frame\n");????????????????????????????????????????????????? ?????????? The relationship between multiple frames is encoded and compressed, so you need to enter multiple frames first
exit (1);??????????????????????????????????????????????????????????????????????????????? ???????????????????? (To be verified!) Before the cotx->gop_size is decided IPPP, an I-frame three P-frame
}
if (!ngot) {???????????????????????????????????????????????????????????? ??????????????????????????????????? Determine if there is a packet generated, if any ngot! = 0
//av free packet (&PKT);
return 1;
}
//printf ("one packet\n");
return 0;
}
void Encodetest (file *fin, file *fout) {??????????????????????????????????????????????///Encoding test, reading YV12 format data, and then H264 encoding, Last Write file
int buffsize = dheight * dwidth * 1.5;?????????????????????????????????????????????? Just one buff at a time, yv12,640x480 the next frame.
Char Buff[buffsize];
int cot = 0;
while (fread (Buff, 1, buffsize, Fin) > 0) {????????????????????????????????????????????????//read one frame
//printf (" One Frame:%lld\n ", curpts);
if (packet frame encoder (buff, buffsize)) {?????????????????????????????????????????????// Determine if there are packet generated
continue;
}
Cot + = fwrite (Pkt.data, 1, pkt.size, fout);??????????????????????????????????????????????//If any, write to file
//printf ("--->%d\n", cot);
}
//For delayed frames??????????????????????????????????????????????????????????????????????????//said earlier, Sometimes you need to enter multiple frames to have packet, but when the file is read ...
while (!packet frame encoder (NULL, 0)) {????????????????????????????????????????????//NULL special parameter tells encoder " No more input frames, please directly encode output packet "
Cot + = fwrite (Pkt.data, 1, pkt.size, fout);????????????????????????????????????????????? Continuous detection until there is no longer a packet generation, indicating that the code is complete
//printf ("--->%d\n", cot);
}
}
int main () {
Char filea[20] = "target.yuv\0";
Char fileb[20] = "encode.264\0";
FILE *fin = fopen (FileA, "RB");
if (!fin) {
printf ("Input File%s not found\n", FileA);
Return
}
FILE *fout = fopen (Fileb, "WB");
Initencoder ();
printf ("Encoder initialized\n");
Encodetest (Fin, fout);
printf ("Encoding completed\n");
free encoder ();
printf ("Encoder free\n");
Fclose (Fin);
Fclose (Fout);
return 0;
}
Decoder module implementation and detail Analysis " The process is basically consistent with the Encoder module, except that some critical processes are inversely related to coding. "
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#define LOG_TAG "Android-ffmpeg-tutorial01"
#define Logi (...) __android_log_print (4, Log_tag, __va_args__);
#define LOGE (...) __android_log_print (6, Log_tag, __va_args__);
#define Dcodeformat av_codec_id_h264
#define PIXFMT av_pix_fmt_yuv420p
#define DWIDTH 640
#define DHEIGHT 480
#define Bitrate 400000
#define PACKETFRAMES 4
#define FRAMERATE 25
int ErrorS = 0, ngot = 0; More than 0 means error
Avcodec *codec;
Avcodeccontext *cotx = NULL;
Avframe *pframe;
Avpacket PKT;
Char *decodeframe = NULL, *DF = NULL;??????????????????????????????????????????????????????? Used to store decoded frames
static void Init_decoder () {???????????????????????????????????????????????????????????????????????????????// Initial dissolve code module, you can notice that the initialization process and encoder are similar
??? int I, j, K;
??? Avcodec_init ();
??? Avcodec_register_all ();
??? codec = Avcodec_find_decoder (Dcodeformat);???????????????????????????????????? Query decoder
??? if (!CODEC) {
??? ??? ErrorS = 1;
??? ??? Logi ("Codec not found\n");
??? ??? Exit (1);
??? }
??? Cotx = AVCODEC_ALLOC_CONTEXT3 (codec);???????????????????????????????????????????????????????? Get Decoder "context"
??? if (!cotx) {
??? ??? ErrorS = 1;
??? ??? Logi ("Could not allocate video codec context\n");
??? ??? Exit (1);
??? }
??? Cotx->bit_rate = bitrate; Set bit rate???????????????????????????????????????????????????????? In FFmpeg's decoding demo, "context" does not have such a setting
??? Cotx->width = Dwidth;????????????????????????????????????????????????????????????????????????????????? It is found that the decoding is based on the encoded packet read to get the "context"
??? Cotx->height = dheight;?????????????????????????????????????????????????????????????????????????????? Information, such as width and height, is obtained after decoding packet and does not need to be set
??? Cotx->time_base = (avrational) {1, framerate};
??? Cotx->gop_size = Packetframes;
??? Cotx->max_b_frames = 0; What
??? Cotx->frame_number = 1
??? COTX->PIX_FMT = pixfmt;
??? if (codec->capabilities&codec_cap_truncated)
??????? Cotx->flags|= codec_flag_truncated; /* We don't send complete frames */
??? if (Avcodec_open2 (Cotx, codec, NULL) < 0) {
??? ??? Logi ("Could not open codec\n");
??? ??? Exit (1);
??? }
??? Pframe = Av_frame_alloc ();
??? if (!pframe) {
??? ??? Logi ("Could not allocate video frame\n");
??? ??? Exit (1);
??? }
??? Av_init_packet (&PKT);
??? Decodeframe = (char*) malloc ((int) (Dheight * dwidth * 1.5));
??? Return
}
static void Free_decoder () {
??? Avcodec_close (COTX);
??? Av_free (COTX);
??? Av_frame_free (&pframe);
??? Free (decodeframe);
}
/*
? * for H264, YV12 frame only
? * Be sure the decoder have been initialized
?*/
static int Packet_frame_decoder (char *enpacket, int bytesize, int *haslen) {
??? Set RAW Data
??? Pkt.data = Enpacket;
??? Pkt.size = ByteSize;
??? printf ("(O... O):%d\n ", bytesize);
??? (*haslen) = Avcodec_decode_video2 (Cotx, Pframe, &ngot, &PKT);
??? printf ("(*... O) \ n ");
??? if ((*haslen) < 0) {
??? ??? Logi ("Error encoding frame\n");
??? ??? ErrorS = 1;
??? ??? Exit (1);
??? }
??? printf ("(!.. O):%d\n ", *haslen);
??? if (!ngot | | cotx->width! = Dwidth | | Cotx->height! = Dheight | | cotx->pix_fmt = PIXFMT) {//failed to decode a Frame
??? ??? ErrorS = 1;??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? STH wrong with Format
??? ??? return 1;
??? }
??? Process decoded data in Pframe
??? DF = decodeframe;
??? Y
??? memcpy (DF, pframe->data[0], pframe->linesize[0] * cotx->height);
??? DF + = pframe->linesize[0] * cotx->height;
??? Cr, Cb
??? memcpy (DF, pframe->data[1], (int) (pframe->linesize[1] * cotx->height/2));
??? DF + = (int) (pframe->linesize[1] * COTX->HEIGHT/2);
??? memcpy (DF, pframe->data[2], (int) (pframe->linesize[2] * cotx->height/2));
??? printf ("=====>>%d\n", pframe->linesize[0] * cotx->height + (int) (pframe->linesize[1] * cotx-> HEIGHT/2) + (int) (pframe->linesize[2] * cotx->height/2));
??? return 0;
}
For each packet, find its header of I Frame
int findiframe (unsigned char *buff, int buffsize) {
??? int ps, len = buffsize-3;
??? for (PS = 0; PS < len; ++ps) {
??? ??? if (buff[ps] = = 0x0 && buff[ps+1] = = 0x0
??? ??? ?&& buff[ps+2] = = 0x0 && buff[ps+3] = = 0x1
??? ??? ? && buff[ps+4] = = 0x67) {
??? ??? ??? return PS;
??? ??? }
??? }
??? return-1;
}
For each packet, the find its header of P Frame
int findpframe (unsigned char *buff, int buffsize) {
??? int ps, len = buffsize-3;
??? for (PS = 0; PS < len; ++ps) {
??? ??? if (buff[ps] = = 0x0 && buff[ps+1] = = 0x0
??? ??? ?&& buff[ps+2] = = 0x0 && buff[ps+3] = = 0x1
??? ??? ? && buff[ps+4] = = 0x41) {
??? ??? ??? return PS;
??? ??? }
??? }
??? return-1;
}
For each packet, find its header of I or P Frame
int findipframe (unsigned char *buff, int buffsize) {
??? int ps, len = buffsize-3;
??? for (PS = 0; PS < len; ++ps) {
??? ??? if (buff[ps] = = 0x0 && buff[ps+1] = = 0x0
??? ??? ?&& buff[ps+2] = = 0x0 && buff[ps+3] = = 0x1) {
??? ??? ???? if (buff[ps+4] = = 0x67 | | buff[ps+4] = = 0x41) {
??? ??? ??? ??? return PS;
??? ??? ??? }
??? ??? }
??? }
??? return-1;
}
Make sure the I-Frame at the top of file
void Decodetest (file *fin, file *fout) {
??? int bufflen = 30720, DEL = 3, COT = 0, tmmp;
??? Char Buff[bufflen];
??? int buffsize = 0, packetsize = 0, Haslen;
??? Buffsize = fread (buff, 1, Bufflen, Fin);
??? if (buffsize <= 0) {
??? ??? printf ("Empty file\n");
??? ??? Return
??? }
??? PacketSize = Findiframe (buff, buffsize);
??? if (PacketSize < 0) {
??? ??? printf ("Can ' t find I frame, broken\n");
??? ??? Return
??? }
??? Buffsize-= PacketSize;
??? Memmove (Buff, buff+packetsize, buffsize);
??? Buffsize + = Fread (buff+buffsize, 1, bufflen-buffsize, Fin);
??? PacketSize = Findipframe (Buff+del, Buffsize-del) + DEL;
??? while (PacketSize > DEL) {//break if can ' t find Next Frame
??? ??? COT + = PacketSize;
??? ??? printf ("%d---%d--->%d\n", buffsize, PacketSize, COT);
??? ??? int t = 0;
??? ??? for (t = 0; t < ++t) {
??? ??? // ??? printf ("%x-", buff[t]);
??? ??? // }
??? ??? printf ("\ n");
??? ??? if (!packet_frame_decoder (Buff, packetsize, &haslen)) {
??? ??? ??? Fwrite (Decodeframe, 1, (int) (Dheight * dwidth * 1.5), fout);
??? ??? }
??? ??? Buffsize-= PacketSize;
??? ??? Memmove (Buff, buff+packetsize, buffsize);
??? ??? Buffsize + = Fread (buff+buffsize, 1, bufflen-buffsize, Fin);
??? ??? PacketSize = Findipframe (Buff+del, Buffsize-del) + DEL;
??? }
??? For the last frame
??? if (!packet_frame_decoder (Buff, buffsize, &haslen)) {
??? ??? Fwrite (Decodeframe, 1, (int) (Dheight * dwidth * 1.5), fout);
??? }
??? For delayed frame
??? while (!packet_frame_decoder (NULL, 0, &haslen)) {
??? ??? Fwrite (Decodeframe, 1, (int) (Dheight * dwidth * 1.5), fout);
??? }
}
int main () {
??? Char filea[20] = "encode.264\0";
??? Char fileb[20] = "decode.yuv\0";
??? FILE *fin = fopen (FileA, "RB");
??? if (!fin) {
??? ??? printf ("Input File%s not found\n", FileA);
??? ??? Return
??? }
??? FILE *fout = fopen (Fileb, "WB");
??? Init_decoder ();
??? Decodetest (Fin, fout);
??? Free_decoder ();
??? Fclose (Fin);
??? Fclose (Fout);
??? return 0;
}
ffmpeg--h264--encoding && decoding C implementation and related principles in Linux