Video Codec-x264 for encoding and FFMPEG for decoding

Source: Internet
Author: User

The project uses video codec, which has been around for the last half a month. To be honest, it has taken a lot of detours and wasted a lot of time. Record your final results here, hoping to help others.

Reference Tutorial:

Http://ffmpeg.org/trac/ffmpeg/wiki/ubuntucompilationguideinstall the ffmpegand x264 official tutorials (be careful not to use command line installation, there will be a lot less libraries. Installation and compilation are the safest)

Http://blog.csdn.net/zgyulongfei/article/details/7526249

Http://www.cnblogs.com/fojian/archive/2012/09/01/2666627.html#good article

Http://my.oschina.net/u/555701/blog/56616? P = 2 # comments-a good decoded article

The overall process is as follows:

The entire process is divided into three parts: Collection, encoding, and decoding.

1. Video collection

I use a USB camera to collect videos. My camera only supports image acquisition in yuv422 format, because the x264 encoding library can only encode the yuv420p (planar) format, therefore, the image data in yuv422 format must be converted to yuv420p format.

You can use the official video collection program to modify the video.

Static void process_image (const char * P); Function

The parameter P points to the YUV data of a captured image.

 

There are many tutorials on YUV and RGB formats.

Here, I will explain my understanding.

Suppose there is a 4*4 resolution image, as shown below:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

Each pixel is composed of YUV data, assuming the following:

Y1

U1

V1

Y2

U2

V2

Y3

U3

V3

Y4

U4

V4

Y5

U5

V5

Y6

U6

V6

Y7

U7

V7

Y8

U8

V8

Y9

U9

V9

Y10

U10

V10

Y11

U11

V11

Y12

U12

V12

Y13

U13

V13

Y14

U14

V14

Y15

U15

V15

Y16

2010.cn

V16

The yuv422 image is like this. Each pixel is Y and UV is collected every two pixels:

In packed format, yuv420 is like this. Each pixel is collected by Y and UV, and each row is collected by every two pixels:

The above formats are stored from left to right, from top to bottom.

I want to get the yuv420 in planar format, that is, in a continuous memory, store all y, then all U, and finally all v.

The modified process_image function is as follows:

static voidprocess_image                   (const char *           p){        //fputc ('.', stdout);//convert yuv422 to yuv420p        char *y=yuv420p;        char *u=&yuv420p[IMAGE_WIDTH*IMAGE_HEIGHT];        char *v=&yuv420p[IMAGE_WIDTH*IMAGE_HEIGHT+IMAGE_WIDTH*IMAGE_HEIGHT/4];        int i=0,j=0,l=0;        for(j=0;j<IMAGE_HEIGHT;j++)        for(i=0;i<IMAGE_WIDTH*2;i++,l++){        if(j%2==0){//even line to sample U-Chriminance        if(l==1){//sample U-Chriminance         *u=p[j*IMAGE_WIDTH*2+i];         u++;         }         else if(l==3){//abandon V-Chromal=-1;         continue;         }         else{         *y=p[j*IMAGE_WIDTH*2+i];         ++y;         }        }        else if(j%2==1){//odd lines to sample  V-Chroma        if(l==1){        continue;        }        else if(l==3){l=-1;        *v=p[j*IMAGE_WIDTH*2+i];        ++v;        }        else {        *y=p[j*IMAGE_WIDTH*2+i];        ++y;        }        }        }        fwrite(yuv420p,IMAGE_WIDTH*IMAGE_HEIGHT*3>>1,1,fp_yuv420p);        fflush (stdout);        }

2.
Encoding

Use the x264 encoding library to encode the yuv420p file.

The procedure is as follows:

#include <stdint.h>#include <x264.h>#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#include <string.h>#define DEBUG 0#define CLEAR(x) (memset((&x),0,sizeof(x)))#define IMAGE_WIDTH   320#define IMAGE_HEIGHT  240#define ENCODER_PRESET "veryfast"#define ENCODER_TUNE   "zerolatency"#define ENCODER_PROFILE  "baseline"#define ENCODER_COLORSPACE X264_CSP_I420typedef struct my_x264_encoder{x264_param_t  * x264_parameter;char parameter_preset[20];char parameter_tune[20];char parameter_profile[20];x264_t  * x264_encoder;x264_picture_t * yuv420p_picture;long colorspace;unsigned char *yuv;x264_nal_t * nal;} my_x264_encoder;char *read_filename="yuv420p.yuv";char *write_filename="encode.h264";intmain(int argc ,char **argv){int ret;int fd_read,fd_write;my_x264_encoder * encoder=(my_x264_encoder *)malloc(sizeof(my_x264_encoder));if(!encoder){printf("cannot malloc my_x264_encoder !\n");exit(EXIT_FAILURE);}CLEAR(*encoder);/**************************************************************************** * Advanced parameter handling functions ****************************************************************************//* These functions expose the full power of x264's preset-tune-profile system for * easy adjustment of large numbers //free(encoder->yuv420p_picture);of internal parameters. * * In order to replicate x264CLI's option handling, these functions MUST be called * in the following order: * 1) x264_param_default_preset * 2) Custom user options (via param_parse or directly assigned variables) * 3) x264_param_apply_fastfirstpass * 4) x264_param_apply_profile * * Additionally, x264CLI does not apply step 3 if the preset chosen is "placebo" * or --slow-firstpass is set. */strcpy(encoder->parameter_preset,ENCODER_PRESET);strcpy(encoder->parameter_tune,ENCODER_TUNE);encoder->x264_parameter=(x264_param_t *)malloc(sizeof(x264_param_t));if(!encoder->x264_parameter){printf("malloc x264_parameter error!\n");exit(EXIT_FAILURE);}CLEAR(*(encoder->x264_parameter));x264_param_default(encoder->x264_parameter);if((ret=x264_param_default_preset(encoder->x264_parameter,encoder->parameter_preset,encoder->parameter_tune))<0){printf("x264_param_default_preset error!\n");exit(EXIT_FAILURE);}encoder->x264_parameter->i_fps_den  =1;encoder->x264_parameter->i_fps_num  =25;encoder->x264_parameter->i_width  =IMAGE_WIDTH;encoder->x264_parameter->i_height =IMAGE_HEIGHT;encoder->x264_parameter->i_threads =1;encoder->x264_parameter->i_keyint_max    =25;encoder->x264_parameter->b_intra_refresh =1;encoder->x264_parameter->b_annexb =1;strcpy(encoder->parameter_profile,ENCODER_PROFILE);if((ret=x264_param_apply_profile(encoder->x264_parameter,encoder->parameter_profile))<0){printf("x264_param_apply_profile error!\n");exit(EXIT_FAILURE);}#if DEBUGprintf("Line --------%d\n",__LINE__);#endifencoder->x264_encoder=x264_encoder_open(encoder->x264_parameter);encoder->colorspace=ENCODER_COLORSPACE;#if DEBUGprintf("Line --------%d\n",__LINE__);#endifencoder->yuv420p_picture=(x264_picture_t *)malloc(sizeof(x264_picture_t ));if(!encoder->yuv420p_picture){printf("malloc encoder->yuv420p_picture error!\n");exit(EXIT_FAILURE);}if((ret=x264_picture_alloc(encoder->yuv420p_picture,encoder->colorspace,IMAGE_WIDTH,IMAGE_HEIGHT))<0){printf("ret=%d\n",ret);printf("x264_picture_alloc error!\n");exit(EXIT_FAILURE);}encoder->yuv420p_picture->img.i_csp=encoder->colorspace;encoder->yuv420p_picture->img.i_plane=3;encoder->yuv420p_picture->i_type=X264_TYPE_AUTO;#if DEBUGprintf("Line --------%d\n",__LINE__);#endifencoder->yuv=(uint8_t *)malloc(IMAGE_WIDTH*IMAGE_HEIGHT*3/2);if(!encoder->yuv){printf("malloc yuv error!\n");exit(EXIT_FAILURE);}CLEAR(*(encoder->yuv));#if DEBUGprintf("Line --------%d\n",__LINE__);#endifencoder->yuv420p_picture->img.plane[0]=encoder->yuv;encoder->yuv420p_picture->img.plane[1]=encoder->yuv+IMAGE_WIDTH*IMAGE_HEIGHT;encoder->yuv420p_picture->img.plane[2]=encoder->yuv+IMAGE_WIDTH*IMAGE_HEIGHT+IMAGE_WIDTH*IMAGE_HEIGHT/4;if((fd_read=open(read_filename,O_RDONLY))<0){printf("cannot open input file!\n");exit(EXIT_FAILURE);}if((fd_write=open(write_filename,O_WRONLY | O_APPEND | O_CREAT,0777))<0){printf("cannot open output file!\n");exit(EXIT_FAILURE);}#if DEBUGprintf("Line --------%d\n",__LINE__);#endifint n_nal;x264_picture_t pic_out;x264_nal_t *my_nal;encoder->nal=(x264_nal_t *)malloc(sizeof(x264_nal_t ));if(!encoder->nal){printf("malloc x264_nal_t error!\n");exit(EXIT_FAILURE);}CLEAR(*(encoder->nal));while(read(fd_read,encoder->yuv,IMAGE_WIDTH*IMAGE_HEIGHT*3/2)>0){encoder->yuv420p_picture->i_pts++;if((ret=x264_encoder_encode(encoder->x264_encoder,&encoder->nal,&n_nal,encoder->yuv420p_picture,&pic_out))<0){printf("x264_encoder_encode error!\n");exit(EXIT_FAILURE);}unsigned int length=0;for(my_nal=encoder->nal;my_nal<encoder->nal+n_nal;++my_nal){write(fd_write,my_nal->p_payload,my_nal->i_payload);length+=my_nal->i_payload;}printf("length=%d\n",length);}/*clean_up functions*///x264_picture_clean(encoder->yuv420p_picture);//free(encoder->nal);//???? confused conflict with x264_encoder_close(encoder->x264_encoder);free(encoder->yuv);free(encoder->yuv420p_picture);free(encoder->x264_parameter);x264_encoder_close(encoder->x264_encoder);free(encoder);close(fd_read);close(fd_write);return 0;}

3. Decoding

Use FFMPEG for decoding

The procedure is as follows:

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libavutil/mathematics.h>#define DECODED_OUTPUT_FORMAT  AV_PIX_FMT_YUV420P#define INPUT_FILE_NAME "encode.h264"#define OUTPUT_FILE_NAME "decode.yuv"#define IMAGE_WIDTH  320#define IMAGE_HEIGHT 240voiderror_handle(const char *errorInfo ){printf("%s error!\n",errorInfo);exit(EXIT_FAILURE);}intmain(int argc,char ** argv){int  write_fd,ret,videoStream;AVFormatContext * formatContext=NULL;AVCodec * codec;AVCodecContext * codecContext;AVFrame * decodedFrame;AVPacket packet;uint8_t *decodedBuffer;unsigned int decodedBufferSize;int finishedFrame;av_register_all();write_fd=open(OUTPUT_FILE_NAME,O_RDWR | O_CREAT,0666);if(write_fd<0){perror("open");exit(1);}ret=avformat_open_input(&formatContext, INPUT_FILE_NAME, NULL,NULL);if(ret<0)error_handle("avformat_open_input error");ret=avformat_find_stream_info(formatContext,NULL);if(ret<0)error_handle("av_find_stream_info");videoStream=0;codecContext=formatContext->streams[videoStream]->codec;codec=avcodec_find_decoder(AV_CODEC_ID_H264);if(codec==NULL)error_handle("avcodec_find_decoder error!\n");ret=avcodec_open2(codecContext,codec,NULL);if(ret<0)error_handle("avcodec_open2");decodedFrame=avcodec_alloc_frame();if(!decodedFrame)error_handle("avcodec_alloc_frame!");decodedBufferSize=avpicture_get_size(DECODED_OUTPUT_FORMAT,IMAGE_WIDTH,IMAGE_HEIGHT);decodedBuffer=(uint8_t *)malloc(decodedBufferSize);if(!decodedBuffer)error_handle("malloc decodedBuffer error!");av_init_packet(&packet);while(av_read_frame(formatContext,&packet)>=0){ret=avcodec_decode_video2(codecContext,decodedFrame,&finishedFrame,&packet);if(ret<0)error_handle("avcodec_decode_video2 error!");if(finishedFrame){avpicture_layout((AVPicture*)decodedFrame,DECODED_OUTPUT_FORMAT,IMAGE_WIDTH,IMAGE_HEIGHT,decodedBuffer,decodedBufferSize);ret=write(write_fd,decodedBuffer,decodedBufferSize);if(ret<0)error_handle("write yuv stream error!");}av_free_packet(&packet);}while(1){packet.data=NULL;packet.size=0;ret=avcodec_decode_video2(codecContext,decodedFrame,&finishedFrame,&packet);if(ret<=0 && (finishedFrame<=0))break;if(finishedFrame){avpicture_layout((AVPicture*)decodedFrame,DECODED_OUTPUT_FORMAT,IMAGE_WIDTH,IMAGE_HEIGHT,decodedBuffer,decodedBufferSize);ret=write(write_fd,decodedBuffer,decodedBufferSize);if(ret<0)error_handle("write yuv stream error!");}av_free_packet(&packet);}avformat_close_input(&formatContext);free(decodedBuffer);av_free(decodedFrame);avcodec_close(codecContext);return 0;}

Result:

1. yuv420p, 11.0 MB in size collected by the USB camera, can be played normally using the pyuv player.

2. The encoded file encode. h264 is 262.4kb in size and can be played normally on the VLC player.

3. The decoded file Decode. YUV is 11.0 MB in size and can be played normally using the pyuv player.

 

Related Files are included in my resources:

1. Collection, encoding, decoding, corresponding executable programs, and makefile files;

2. pyuv player (for XP)

3. Experiment file-yuv420p. YUV, encode. h264, decode. YUV

4. PDF

Thank you for your criticism!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.