ffmpeg+sdl2.0 Streaming Media Development 3---Simple MP4 video player, extract MP4 H264 video sequence decoding and display

Source: Internet
Author: User

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,&AMP;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-&GT;CODEC-&GT;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, &AMP;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-&GT;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, &AMP;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 (&AMP;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

Related Article

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.