Brief introduction
Previously wrote the extract MP4 in the audio and video and decoding, this article introduced SDL2.0 to display the decoded video sequence to achieve a simple video player.
I use the ffmpeg and SDL2.0 are the latest version of the possible online information is not many, API interface has changed a lot, but the general idea is the same.
Analyze several ffmpeg functions
Before we analyze the source code for several of the ffmpeg functions that may be problematic in several codes, I have added comments as much as I can, because there is no document that may be in a very detailed, but largely readable, place.
Av_image_alloc (assigning picture buffers)
We quoted this function in FFmpeg, and the functions listed below are all referenced in this function. I've added a note here.
The pointers parameter is an array of pointers in fact he will be assigned a sequential memory sequence after initialization to see the source code.
int Av_image_alloc (uint8_t *pointers[4], int linesizes[4], int w, int h, enum avpixelformat pix_fmt, int Align) {//Get descriptor const Avpixfmtdescriptor *DESC = Av_pix_fmt_desc_get (PIX_FMT); int I, ret; uint8_t *buf; If there is no descriptor then return error if (!DESC) return Averror (EINVAL); Detects image width Height if (ret = Av_image_check_size (w, h, 0, NULL)) < 0) return ret; Populate line Sizes if (ret = av_image_fill_linesizes (linesizes, pix_fmt, align>7?). Ffalign (W, 8): W)) < 0) return ret; Initialize 0 for (i = 0; i < 4; i++) linesizes[i] = Ffalign (Linesizes[i], align); If the calculated buffer size is <0 if (ret = av_image_fill_pointers (pointers, Pix_fmt, H, NULL, linesizes)) < 0) return ret; If the failure is reassigned buf BUF = av_malloc (ret + align); if (!BUF) return Averror (ENOMEM); Call again to assign a continuous buffer assignment to pointers if (ret = av_image_fill_pointers (pointers, Pix_fmt, H, buf, linesizes)) < 0) {//AS If the allocation fails, then the buffer is freed Av_free (BUF); return ret; }//Detect pixel descriptor Av_pix_fmt_flag_pal or Av_pix_fmt_flag_pseudopal//pixel format has a palette in data[1], values is indexes in This palette./**the pixel format is "pseudo-paletted". This means, FFmpeg treats it as* paletted internally, but the palette was generated by the decoder and is not* stored I n the file. **/if (desc->flags & Av_pix_fmt_flag_pal | | Desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL)//Set System palette Avpriv_set_systematic_pal2 ((uint32_t*) pointers[1], pix_fmt); return ret;}
Avpriv_set_systematic_pal2 (set system palette)
Set up a systematic palette based on different pixel formats
int Avpriv_set_systematic_pal2 (uint32_t pal[256], enum Avpixelformat pix_fmt) {int i; for (i = 0; i < i++) {int R, G, B; Switch (PIX_FMT) {Case av_pix_fmt_rgb8:r = (i>>5) *36; g = ((i>>2) &7) *36; b = (i&3) *85; Break Case av_pix_fmt_bgr8:b = (i>>6) *85; g = ((i>>3) &7) *36; R = (i&7) *36; Break Case av_pix_fmt_rgb4_byte:r = (i>>3) *255; g = ((i>>1) &3) *85; b = (i&1) *255; Break Case av_pix_fmt_bgr4_byte:b = (i>>3) *255; g = ((i>>1) &3) *85; R = (i&1) *255; Break Case Av_pix_fmt_gray8:r = b = g = i; Break Default:return Averror (EINVAL); } Pal[i] = B + (g << 8) + (R << 16) +(0xFFU << 24); } return 0;}
Av_image_fill_pointers (unsigned char** data and linesize that populate the Av_image_alloc pass)
Returns the desired size of the image//and allocates a contiguous buffer to stitch data into a contiguous sequence of memory int av_image_fill_pointers (uint8_t *data[4], enum Avpixelformat pix_fmt, int Height, uint8_t *ptr, const int linesizes[4]) {int I, total_size, size[4] = {0}, HAS_PL Ane[4] = {0}; Get Descriptor const Avpixfmtdescriptor *DESC = Av_pix_fmt_desc_get (PIX_FMT); Empties the pointer array memset (data, 0, sizeof (data[0)); If there is no descriptor return error if (!desc | | Desc->flags & av_pix_fmt_flag_hwaccel) return Averror (EINVAL); Data[0] initialized to ptr data[0] = ptr; If the pixel of each line is greater than the INT type maximum -1024/height returns if (Linesizes[0] > (int_max-1024)/height) return averror (EINVAL); Initialize size[0] size[0] = linesizes[0] * height; If the descriptor's flag is Av_pix_fmt_flag_pal or Av_pix_fmt_flag_pseudopal then the palette is placed in data[1] and is 256 32 position if (Desc->flags & AV_PI X_fmt_flag_pal | | Desc->flags & Av_pix_fmt_flag_pseudopal) {size[0] = (Size[0] + 3) & ~; Data[1] = ptr + size[0]; return size[0] + 256 * 4; }/** * Parameters that describe how pixels is packed. * If The format has a 2 or 4 components and then Alpha was last. * If The format has 1 or 2 components and then Luma is 0. * If the format has 3 or 4 components, * If the RGB flag is set then 0 is red, 1 was green and 2 is blue; * Otherwise 0 is luma, 1 are chroma-u and 2 is chroma-v. */for (i = 0; i < 4; i++) Has_plane[desc->comp[i].plane] = 1;//The following is the calculation of the total required buffer size total_size = size[0]; for (i = 1; i < 4 && has_plane[i]; i++) {int h, s = (i = = 1 | | i = = 2)? desc->log2_chroma_h:0; Data[i] = Data[i-1] + size[i-1]; H = (height + (1 << s)-1) >> s; if (Linesizes[i] > int_max/h) return Averror (EINVAL); Size[i] = h * linesizes[i]; if (Total_size > Int_max-size[i]) return Averror (EINVAL); Total_size + = Size[i]; }//Returns the total buffer size return total_size;}
Av_image_fill_linesizes (fill line width)
Fills the linesize array, linesize represents each new line width pixel as an int av_image_fill_linesizes (int linesizes[4], enum Avpixelformat pix_fmt, int width) { int i, ret;//gets the format descriptor const Avpixfmtdescriptor *DESC = Av_pix_fmt_desc_get (pix_fmt); int Max_step [4]; /* Max pixel step for each plane */ int max_step_comp[4]; /* The component for each plane which have the max pixel step *// Initialize pointer array 0 memset (linesizes, 0, 4*sizeof (linesize S[0])); If not present then return error if (!desc | | Desc->flags & av_pix_fmt_flag_hwaccel) return Averror (EINVAL); The code below is filled with line width code av_image_fill_max_pixsteps (max_step, Max_step_comp, desc); for (i = 0; i < 4; i++) { if (ret = image_get_linesize (width, I, max_step[i], max_step_comp[i], desc)) < 0)
return ret; Linesizes[i] = ret; } return 0;}
Example extract MP4 file video and play to implement a simple video player
#include "stdafx.h"/************************************************************************//* Shunt MP4 file audio and video using a shunt and decode the output programmer little Wei-usher 2014/12/17/*********************************************************** Open # define __stdc_format_macros#ifdef _cpprtti extern "C" {#endif # include "Libavutil/imgutils.h"// The image tool #include "libavutil/samplefmt.h"//Audio sample format # include "Libavutil/timestamp.h"//timestamp tool can be used for debugging and logging purposes #include "libavfor Mat/avformat.h "//main Libavformat public API header contains LIBAVF I/O and demuxing and muxing libraries #include" SDL.h "#ifdef _CPPRT TI}; #endif//Audio Video encoder context static Avcodeccontext *pvideocontext,*paudiocontext;static FILE *fvideofile,*faudiofile; Output file handle static Avstream *pstreamvideo,*pstreamaudio; Media stream Static unsigned char * videodstdata[4]; Video data static int videolinesize[4]; static int videobuffersize; Video buffer size static avformatcontext *pformatctx=null; Format context static avframe*pframe=null; Static Avpacket pkt; Decode media packet static int ret=0; State static int GOtframe; Get to the video stream//audio/video stream index static int videostreamindex,audiostreamindex;//decode Media pack//sdl definition Sdl_window * pwindow = NULL; Sdl_renderer *prender = NULL; Sdl_texture *ptexture = NULL; Sdl_rect dstrect = {0,0,800,600};int frame = 0;int indexframevideo=0;static int decode_packet (int* gotFrame, int param2) {i NT ret = 0;//decode data size int decodedsize=pkt.size; Initialize the captured data frame to 0*gotframe=0;//if it is a video stream then unpack the video stream if (pkt.stream_index==videostreamindex) {//decode the data to the video frame if (ret=avcodec_ Decode_video2 (PVIDEOCONTEXT,PFRAME,GOTFRAME,&PKT)) <0) {//decode video frame failed return ret;} Indexframevideo++;//copy extracted data into our allotted space if (*gotframe) {//Copy data av_image_copy (Videodstdata,videolinesize, (const uint8_t * *) (Pframe->data), pframe->linesize,pvideocontext->pix_fmt, Pvideocontext->width, Pvideocontext->height);//write data to Buffer//fwrite (videodstdata[0], 1, videobuffersize, fvideofile); printf ("Output current%d frame, size:%d\n", indexframevideo,videobuffersize); int n = sdl_bytesperpixel (PSTREAMVIDEO->CODEC->PIX_FMT);//Update Texture sdl_updatetexture (PTExture, &dstrect, (const void*) videodstdata[0], videolinesize[0]);//copy Texture to 2D module sdl_rendercopy (Prender, Ptexture, NULL, &dstrect);//Delay 1000ms*1/25sdl_delay ($ * 1/frame);//show Render Render has sdl_renderpresent (Prender);} else{printf ("frame%d, lost \ n", Indexframevideo);}} Audio regardless of else if (Pkt.stream_index==audiostreamindex) {///Decode audio information//if (ret = Avcodec_decode_audio4 (Paudiocontext, pframe , Gotframe, &PKT)) < 0)//return ret;//decodedsize = ffmin (ret, pkt.size);//////Calculate the size of the current frame//size_t unpadded_linesize = Pframe->nb_samples * Av_get_bytes_per_sample ((Avsampleformat) pframe->format); Write data to audio file//fwrite (Pframe->extended_data[0], 1, unpadded_linesize, faudiofile); }//Cancels all references and resets the frame field av_frame_unref (pframe); return decodedsize;} int demuxing (int argc, char** argv) {if (ARGC < 4) {printf ("Parameter error!\n"); return 0;} Register all mixer Filters Av_register_all ();//Register All encoders Avcodec_register_all ();//Media input source char*pinputfile = argv[1];//Video Output file char* Poutputvideofile = argv[3];//Audio output file Char*poutputaudiofile = argv[2];//Assign Environment Context Pformatctx = Avformat_alloc_context (),//open input source and read header of input source if (Avformat_open_input (& Pformatctx, pinputfile, NULL, NULL) < 0) {printf ("Open Input error!\n"); return 0;} Get Streaming media information if (Avformat_find_stream_info (Pformatctx, NULL) < 0) {printf ("Get streaming media information failed!\n"); return 0;} Print media information Av_dump_format (pformatctx, 0, pinputfile, 0); for (unsigned i = 0; i < pformatctx->nb_streams; i++) {Avstream *pstream = pformatctx->streams[i]; Avmediatype mediatype = pstream->codec->codec_type;//Extract different codecs if (mediatype = = Avmedia_type_video) { Videostreamindex = I;pvideocontext = Pstream->codec;pstreamvideo = Pstream;fvideofile = fopen (POutputVideoFile, "WB" ); frame = Pvideocontext->framerate.num;if (!fvideofile) {printf ("con ' t open file!\n"); goto end;} Calculates the size of a frame image after decoding//int nsize = avpicture_get_size (pix_fmt_yuv420p, 1280, 720);//allocation calculation initialize image buffer palette data int ret = Av_image_alloc (Videodstdata, Videolinesize, Pvideocontext->width, Pvideocontext->height, PVIDEOCONTEXT->PIX_FMT, 1), if (Ret < 0) {printf ("Alloc video buffer error!\n"); goto end;} Avpicture_fill ((Avpicture *) pframe, videodstdata[0], pix_fmt_yuv420p, 1280x720, 720); videobuffersize = ret;} else if (mediatype = = Avmedia_type_audio) {audiostreamindex = I;paudiocontext = Pstream->codec;pstreamaudio = PStream; Faudiofile = fopen (Poutputaudiofile, "WB"), if (!faudiofile) {printf ("con ' t open file!\n"); goto end;} Assign video Frame pframe = Av_frame_alloc (), if (pframe = = NULL) {av_freep (&videodstdata[0]);p rintf ("Alloc Audio frame error\n" ); goto end;}} Avcodec *dec;//Find Encoder dec = avcodec_find_decoder (pstream->codec->codec_id) based on encoder ID, if (dec = = NULL) {printf (" Find encoder failed!\n "); goto end;} if (Avcodec_open2 (Pstream->codec, Dec, nullptr)! = 0) {printf ("Open encoder failed!\n"); goto end;}} Av_init_packet (&pkt);p kt.data = Null;pkt.size = 0;//Read Media packet data is greater than or equal to 0while (Av_read_frame (Pformatctx, &PKT) >= 0) {avpacket ORIPKT = pkt;do{//Returns the data decoded by each packet ret = decode_packet (&gotframe, 0); if (Ret < 0) break;//pointer back free memory decrease PKT . Data + = RET;Pkt.size-= ret;//} while (Pkt.size > 0);//release of the allocated space prior to reading must release the package Av_free_packet (&ORIPKT);} end://turn off the video encoder avcodec_close (pvideocontext);//Turn off the Audio encoder avcodec_close (paudiocontext); Avformat_close_input (& PFORMATCTX); fclose (fvideofile); fclose (faudiofile);//release encoded frame Avcodec_free_frame (&pframe);//release video data area av_free ( Videodstdata[0]); return 0;} int _tmain (int argc, char*argv[]) {sdl_init (sdl_init_video); Create Window Pwindow = Sdl_createwindow ("yuv420p", 200, 100, 800, 600, 0);//Enable hardware acceleration prender=sdl_createrenderer (Pwindow,-1, 0); Dstrect.x = 0;dstrect.y = 0;DSTRECT.W = 1280;dstrect.h = 720;//Create a texture setting can be lock yuv420p format 1280*720 ptexture = sdl_create Texture (Prender, SDL_PIXELFORMAT_IYUV, sdl_textureaccess_streaming, 1280x720, 720);D emuxing (argc, argv);//Release Sdl_ Renderclear (Prender); Sdl_destroytexture (ptexture); Sdl_destroyrenderer (Prender); Sdl_destroywindow (Pwindow); Sdl_quit (); return 0;}
Code Run Interface
ffmpeg+sdl2.0 Streaming Media Development 3---Simple MP4 video player, extract MP4 H264 video sequence decoding and display