使用ffmpeg为库编写的小型多媒体播放器源代码

使用ffmpeg为库编写的小型多媒体播放器源代码

 

今天突发奇想,就在以前音频播放器(详细情况请看这里——http://blog.csdn.net/baymoon/archive/2006 /11/16/1388693.aspx)的基础上用ffmpeg写了个简单的多媒体播放器,这里把源代码贴出来,供大家参评;这里的多媒体播放,并没有 用到什么很强大的音视频同步技术,而只是简单的使用了视频随着音频同步,想必你看了代码之后会有所悟的。。。不多说了,看代码。。。 /* **************************************************************************
 *            main.cc
 *
 *  Thu Nov  9 20:47:33 2006
 *  Copyright  2006 
 *  Email lsosa.cs2c
 ***************************************************************************
*/



#include 
< avcodec.h >
#include 
< avformat.h >
#include 
< avutil.h >
#include 
< assert.h >
#include 
< stdio.h >
#include 
< stdlib.h >
#include 
< X11 / Xlib.h >
#include 
< sys / soundcard.h >
#include 
< sys / stat.h >
#include 
< fcntl.h >
#include 
< sys / ioctl.h >
#include 
< unistd.h >
#include 
< errno.h >
#include 
< string .h >
#include 
< sched.h >
#include 
< SDL / SDL.h >

#define  ALL_DEBUG

#ifdef ALL_DEBUG
    
#define  AV_DEBUG
    
#define  AUDIO_DEBUG
#endif

// ------------------------------------------------------------------------------
//  manipulations for file
int  open_file ( char   * file_name,  int  mode)
{
    
//  open file file_name and return the file descriptor;
     int  fd;

    
if  ((fd  =  open (file_name, mode))  <   0 )
    
{
        fprintf (stderr, 
"  Can't open %s! " , file_name);
        exit (
- 1 );
    }

    
return  fd;
}


int  set_audio ( int  fd, AVCodecContext  *  pCodecCtx)
{
    
//  set the properties of audio device with pCodecCtx;

    
int  i, err;
    
/*  设置适当的参数,使得声音设备工作正常  */
    
/*  详细情况请参考Linux关于声卡编程的文档  */
    
    i 
=   0 ;
    ioctl (fd, SNDCTL_DSP_RESET, 
& i);
    i 
=   0 ;
    ioctl (fd, SNDCTL_DSP_SYNC, 
& i);
    i 
=   1 ;
    ioctl (fd, SNDCTL_DSP_NONBLOCK, 
& i);
    
    
//  set sample rate;
    #ifdef AUDIO_DEBUG
    printf (
" pCodecCtx->sample_rate:%d " , pCodecCtx -> sample_rate);
    
#endif
    i 
=  pCodecCtx -> sample_rate;
    
if  (ioctl (fd, SNDCTL_DSP_SPEED,  & i)  ==   - 1 )
    
{
        fprintf (stderr, 
" Set speed to %d failed:%s " , i,
             strerror (errno));
        
return  ( - 1 );
    }

    
if  (i  !=  pCodecCtx -> sample_rate)
    
{
        fprintf (stderr, 
" do not support speed %d,supported is %d " ,
             pCodecCtx
-> sample_rate, i);
        
return  ( - 1 );
    }

    
    
//  set channels;
    i  =  pCodecCtx -> channels;
    #ifdef AUDIO_DEBUG
    printf (
" pCodecCtx->channels:%d " , pCodecCtx -> channels);
    
#endif
    
if  ((ioctl (fd, SNDCTL_DSP_CHANNELS,  & i))  ==   - 1 )
    
{
        fprintf (stderr, 
" Set Audio Channels %d failed:%s " , i,
             strerror (errno));
        
return  ( - 1 );
    }

    
if  (i  !=  pCodecCtx -> channels)
    
{
        fprintf (stderr, 
" do not support channel %d,supported %d " ,
            pCodecCtx
-> channels, i);
        
return  ( - 1 );
    }

    
//  set bit format;
    i  =  AFMT_S16_LE;
    
if  (ioctl (fd, SNDCTL_DSP_SETFMT,  & i)  ==   - 1 )
    
{
        fprintf (stderr, 
" Set fmt to bit %d failed:%s " , i,
             strerror (errno));
        
return  ( - 1 );
    }

    
if  (i  !=  AFMT_S16_LE)
    
{
        fprintf (stderr, 
" do not support bit %d, supported %d " ,
             AFMT_S16_LE, i);
        
return  ( - 1 );
    }

    
    
//  set application buffer size;
    
//  i = (0x00032 << 16) + 0x000c;         //  32 4kb buffer;
    
//  ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &i);
    i  =   1 ;
    ioctl (fd, SNDCTL_DSP_PROFILE, 
& i);
    
    
return   0 ;
}


void  close_file ( int  fd)
{
    
//  close the file pointed by file descriptor fd;
    close (fd);
}


// ------------------------------------------------------------------------------
//  handle audio;

void  display_AVCodecContext(AVCodecContext  * pCodecCtx) {
    
//
     #define  STDOUT stderr
    fprintf(STDOUT, 
" pCodecCtx->bit_rate:%d " , pCodecCtx -> bit_rate);
    fprintf(STDOUT, 
" pCodecCtx->sample_rate:%d " , pCodecCtx -> sample_rate);
    fprintf(STDOUT, 
" pCodecCtx->channels:%d " , pCodecCtx -> channels);
    fprintf(STDOUT, 
" pCodecCtx->frame_size:%d " , pCodecCtx -> frame_size);
    fprintf(STDOUT, 
" pCodecCtx->frame_number:%d " , pCodecCtx -> frame_number);
    fprintf(STDOUT, 
" pCodecCtx->delay:%d " , pCodecCtx -> delay);
    fprintf(STDOUT, 
" pCodecCtx->frame_bits:%d " , pCodecCtx -> frame_bits);
}


//  error if return -1;
//  success if return 0;
//  这里要用到指向指针的指针,否则传不到值;
int  av_init ( char   * file_name, AVFormatContext  **  pFormatCtx,
    AVCodecContext 
**  pAudioCodecCtx,  int   * p_audioStream, 
    AVCodecContext 
**  pVideoCodecCtx,  int   * p_videoStream)
{
    
//  init the codec and format of input file file_name;
     int  audioStream, i;
    
int  videoStream;
    AVCodec 
* pAudioCodec;
    AVCodec 
* pVideoCodec;
    
//  catch error
    assert(file_name  !=  NULL);
    assert(
* pFormatCtx  !=  NULL);
    assert(
* pAudioCodecCtx  !=  NULL);
    
    
//  Register all formats and codecs
    av_register_all ();
    
    
//  open file
     if  (av_open_input_file (pFormatCtx, file_name, NULL,  0 , NULL)  !=   0 ) {
        
//  Couldn't open file
        fprintf (stderr,  "  Can't open %s! " , file_name);
        
return   - 1 ;    
    }


    
//  Retrieve stream information
     if  (av_find_stream_info ( * pFormatCtx)  <   0 ) {
        
//  Couldn't find stream information
         return   - 1 ;    
    }

    
    #ifdef AV_DEBUG
    
//  Dump information about file onto standard error
    dump_format ( * pFormatCtx,  0 , file_name,  false );
    
#endif
    
    
//  Find the first audio and video stream respectively
    audioStream  =   - 1 ;
    videoStream 
=   - 1 ;
    
for  (i  =   0 ; i  <  ( * pFormatCtx) -> nb_streams; i ++ ) {
        
if  (( * pFormatCtx) -> streams[i] -> codec -> codec_type  ==
            CODEC_TYPE_AUDIO)
        
{
            audioStream 
=  i;
        }
else   if  (( * pFormatCtx) -> streams[i] -> codec -> codec_type  ==
            CODEC_TYPE_VIDEO)
{
            videoStream 
=  i;
        }

    }

    
    #ifdef AV_DEBUG
    
//  dump_stream_info(pFormatCtx);
     #endif
    
    
//  exclude error
     if  (audioStream  ==   - 1 ) {
        
//  Didn't find a audio or video stream
        
//  return -1;    
        printf( " No Audio " );
    }

    
if  (videoStream  ==   - 1 ) {
        
//  Didn't find a audio or video stream
        
//  return -1;    
        printf( " No Video " );
    }


    
//  Get a pointer to the codec context for the audio stream
     * pAudioCodecCtx  =  ( * pFormatCtx) -> streams[audioStream] -> codec;
    
* pVideoCodecCtx  =  ( * pFormatCtx) -> streams[videoStream] -> codec;

    
//  Find the decoder for the audio stream
    pAudioCodec  =  avcodec_find_decoder (( * pAudioCodecCtx) -> codec_id);
    pVideoCodec 
=  avcodec_find_decoder (( * pVideoCodecCtx) -> codec_id);
    
//  
     if  (pAudioCodec  ==  NULL) {
        
return   - 1 ;     //  Codec not found
    }

    
if  (pVideoCodec  ==  NULL) {
        
return   - 1 ;     //  Codec not found
    }


    
//  Open audio codec
     if  (avcodec_open (( * pAudioCodecCtx), pAudioCodec)  <   0 ) {
        
return   - 1 ;     //  Could not open codec
    }

    
//  Open video codec
     if  (avcodec_open (( * pVideoCodecCtx), pVideoCodec)  <   0 ) {
        
return   - 1 ;     //  Could not open codec
    }

    
    #ifdef AUDIO_DEBUG
    
//  printf ("pCodecCtx->sample_rate:%d, audioStream:%d ", (*pCodecCtx)->sample_rate, audioStream);
    
//  display_AVCodecContext(*pCodecCtx);
     #endif
    
    
* p_audioStream  =  audioStream;
    
* p_videoStream  =  videoStream;
    
    
return   0 ;
}


void  av_play (AVFormatContext  *  pFormatCtx,
    AVCodecContext 
*  pAudioCodecCtx,  int  audioStream, 
    AVCodecContext 
*  pVideoCodecCtx,  int  videoStream)
    
//  AVCodecContext * pCodecCtx, int audioStream)
{
    
//  which was read from one frame;
    AVPacket packet;
    uint32_t len;
    uint8_t decompressed_audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE 
*   3 /   2 ];
    
int  decompressed_audio_buf_size;
    uint8_t 
*  p_decompressed_audio_buf;
    
int  fd  =   - 1 ;     //  audio file or test file?
     char  filename[ 64 =   " /dev/dsp " ;
    
int  mode  =  O_WRONLY;
    
//  Video;
    AVFrame  * pFrame;
    AVFrame 
* pFrameYUV;
    
int  frameFinished;
    
    
/  SDL initialization
    SDL_Surface  * screen  =
    SDL_SetVideoMode (pVideoCodecCtx
-> width, pVideoCodecCtx -> height,  0 , SDL_HWSURFACE);
    SDL_Overlay 
* overlay  =
    SDL_CreateYUVOverlay (pVideoCodecCtx
-> width, pVideoCodecCtx -> height,
              SDL_YV12_OVERLAY,
              screen);
    
static  SDL_Rect rect;
    rect.x 
=   0 ;
    rect.y 
=   0 ;
    rect.w 
=  pVideoCodecCtx -> width;
    rect.h 
=  pVideoCodecCtx -> height;
    
/ /
    
    
//  open audio file or written file
    
//  printf("fd:%d", fd);
    fd  =  open_file(filename, mode);
    
//  printf("fd:%d", fd);
    
//  
    set_audio(fd, pAudioCodecCtx);
    
    
//
    printf( " (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2=%d " , (AVCODEC_MAX_AUDIO_FRAME_SIZE  *   3 /   2 );
    printf(
" AVCODEC_MAX_AUDIO_FRAME_SIZE=%d " , AVCODEC_MAX_AUDIO_FRAME_SIZE);
    
    
//  for a test
    
//  char test_file[256] = "my_pcm.pcm";
    
//  fd = open_file(test_file, mode);
    
    #ifdef AV_DEBUG
    
static   int  size  =   0 ;
    
#endif
    
//
    
    
//  set the sched priority
    
//  这是为了提高音频优先级;不晓得起作用没;
     int  policy  =  SCHED_FIFO;
    sched_setscheduler(
0 , policy, NULL);
    
    
//  Allocate video frame
    pFrame  =  avcodec_alloc_frame ();
    
//  Allocate an AVFrame structure
    pFrameYUV  =  avcodec_alloc_frame ();
    
if  (pFrameYUV  ==  NULL)
        
return ;
    
    
//  Set SDL events
    SDL_EventState (SDL_ACTIVEEVENT, SDL_IGNORE);
    SDL_EventState (SDL_MOUSEMOTION, SDL_IGNORE);
    
//  SDL_ShowCursor (SDL_ENABLE);
    
    
int  write_buf_size  =   4196 ;
    
int  written_size;
    
while  ((av_read_frame (pFormatCtx,  & packet)  >=   0 )
        
&&  (SDL_PollEvent (NULL)  ==   0 ))
    
{
        
//  Is this a packet from the audio stream?
        
//  判断是否音频帧;
         if  (packet.stream_index  ==  audioStream)
        
{
            
//  Decode audio frame
            
//  解码音频数据为pcm数据;
            len  =  avcodec_decode_audio (pAudioCodecCtx,  
                            (int16_t 
* )decompressed_audio_buf, 
                            
& decompressed_audio_buf_size,         //  it is the decompressed frame in BYTES 解码后的数据大小,字节为单位;
                            packet.data, 
                            packet.size );
            
//  printf("len:%d, packet.size:%d ", len, packet.size);
            
//  printf("packet.pts:%d packet.dts:%d ", packet.pts, packet.dts);
             if  ( len  <   0  ) {
                
//  if error len = -1
                printf( " +----- error in decoding audio frame " );
                
//  exit(0);
            }

            
//  audio_buf_info info;
            p_decompressed_audio_buf  =  decompressed_audio_buf;
            
while  ( decompressed_audio_buf_size  >   0  ) {
                
//  解码后数据不为零,则播放之,为零,则;
                written_size  =  write(fd, p_decompressed_audio_buf, decompressed_audio_buf_size);
                
if  ( written_size  ==   - 1  ) {
                    
//  printf("error:decompressed_audio_buf_size:%d, decompressed_audio_buf_size:%d, %s ", 
                                decompressed_audio_buf_size, decompressed_audio_buf_size,strerror(errno));
                    
//  usleep(100);
                     continue ;
                }

                
//  printf("decompressed_audio_buf_size:%d, written_size:%d ", 
                            decompressed_audio_buf_size, written_size);
                decompressed_audio_buf_size 
-=  written_size;
                p_decompressed_audio_buf 
+=  written_size;
            }
//  end while
        }

        
else   if  (packet.stream_index  ==  videoStream)
        
{
            
//  Decode video frame
            avcodec_decode_video (pVideoCodecCtx, pFrame,  & frameFinished,
                    packet.data, packet.size);
            
//  Did we get a video frame?
             if  (frameFinished)  {
            
//  Convert the image from its native format to YUV, and display
            
            SDL_LockYUVOverlay (overlay);
            pFrameYUV
-> data[ 0 =  overlay -> pixels[ 0 ];
            pFrameYUV
-> data[ 1 =  overlay -> pixels[ 2 ];
            pFrameYUV
-> data[ 2 =  overlay -> pixels[ 1 ];
            
            pFrameYUV
-> linesize[ 0 =  overlay -> pitches[ 0 ];
            pFrameYUV
-> linesize[ 1 =  overlay -> pitches[ 2 ];
            pFrameYUV
-> linesize[ 2 =  overlay -> pitches[ 1 ];
            
            img_convert ((AVPicture 
* ) pFrameYUV, PIX_FMT_YUV420P, 
                        (AVPicture 
* ) pFrame, pVideoCodecCtx -> pix_fmt, 
                        pVideoCodecCtx
-> width, pVideoCodecCtx -> height);
            SDL_UnlockYUVOverlay (overlay);
            SDL_DisplayYUVOverlay (overlay, 
& rect);
            
///
             //  SDL_Delay (33);
            }

        }
//  end if
        
//  Free the packet that was allocated by av_read_frame
        av_free_packet ( & packet);
    }
//  end while of reading one frame;
    
    
//  Free the RGB image
    av_free (pFrameYUV);
    
//  Free the YUV frame
    av_free (pFrame);
    
//  for test lsosa
    
//  printf("size = %d ", size / 1024 / 1024 );
    SDL_FreeYUVOverlay (overlay);
    
    close_file(fd);
}


void  av_close (AVFormatContext  *  pFormatCtx, AVCodecContext  *  pAudioCodecCtx, 
    AVCodecContext 
*  pVideoCodecCtx)
{
    
//  close the file and codec
    
//  Close the codec
    avcodec_close (pAudioCodecCtx);
    
//  Close the codec
    avcodec_close (pVideoCodecCtx);

    
//  Close the video file
    av_close_input_file (pFormatCtx);
}


// ------------------------------------------------------------------------------

int  main ( int  argc,  char   ** argv) {
    
//
    AVFormatContext  * pFormatCtx;
    
int  audioStream  =   - 1 ;
    
int  videoStream  =   - 1 ;
    AVCodecContext 
* pAudioCodecCtx;
    AVCodecContext 
* pVideoCodecCtx;
    
    
//  exclude the error about args;
     if  ( argc  !=   2  ) {
        printf(
" please give a file name " );
        exit(
0 );
    }

    
    
//  注意:这里要用到指向指针的指针,是因为这个初始化函数需要对指针的地址进行改动,
    
//  所以,只有这么做,才能达到目的;
     if  ( av_init(argv[ 1 ],  & pFormatCtx,  & pAudioCodecCtx,  & audioStream,  & pVideoCodecCtx,  & videoStream)  <   0  ) {
        
//
        fprintf(stderr,  " error when av_init " );
    }

    
    
//  play the audio file
    av_play(pFormatCtx, pAudioCodecCtx, audioStream, pVideoCodecCtx, videoStream);
    
    
//  close all the opend files
    av_close(pFormatCtx, pAudioCodecCtx, pVideoCodecCtx);
    
}

 

来至:http://blog.csdn.net/baymoon/archive/2007/03/15/1530629.aspx

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值