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

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

 
 
  1. /**//***************************************************************************  
  2.  *            main.cc  
  3.  *  
  4.  *  Thu Nov  9 20:47:33 2006  
  5.  *  Copyright  2006   
  6.  *  Email lsosa.cs2c  
  7.  ****************************************************************************/ 
  8. #include <avcodec.h>  
  9. #include <avformat.h>  
  10. #include <avutil.h>  
  11. #include <assert.h>  
  12. #include <stdio.h>  
  13. #include <stdlib.h>  
  14. #include <X11/Xlib.h>  
  15. #include <sys/soundcard.h>  
  16. #include <sys/stat.h>  
  17. #include <fcntl.h>  
  18. #include <sys/ioctl.h>  
  19. #include <unistd.h>  
  20. #include <errno.h>  
  21. #include <string.h>  
  22. #include <sched.h>  
  23. #include <SDL/SDL.h>  
  24.  
  25. #define ALL_DEBUG  
  26.  
  27. #ifdef ALL_DEBUG  
  28.     #define AV_DEBUG  
  29.     #define AUDIO_DEBUG  
  30. #endif  
  31.  
  32. //------------------------------------------------------------------------------  
  33. // manipulations for file  
  34. int open_file (char *file_name, int mode)  
  35. {  
  36.     // open file file_name and return the file descriptor;  
  37.     int fd;  
  38.  
  39.     if ((fd = open (file_name, mode)) < 0)  
  40.     {  
  41.         fprintf (stderr, " Can't open %s! ", file_name);  
  42.         exit (-1);  
  43.     }  
  44.     return fd;  
  45. }  
  46.  
  47. int set_audio (int fd, AVCodecContext * pCodecCtx)  
  48. {  
  49.     // set the properties of audio device with pCodecCtx;  
  50.  
  51.     int i, err;  
  52.     /**//* 设置适当的参数,使得声音设备工作正常 */ 
  53.     /**//* 详细情况请参考Linux关于声卡编程的文档 */ 
  54.       
  55.     i = 0;  
  56.     ioctl (fd, SNDCTL_DSP_RESET, &i);  
  57.     i = 0;  
  58.     ioctl (fd, SNDCTL_DSP_SYNC, &i);  
  59.     i = 1;  
  60.     ioctl (fd, SNDCTL_DSP_NONBLOCK, &i);  
  61.       
  62.     // set sample rate;  
  63.     #ifdef AUDIO_DEBUG  
  64.     printf ("pCodecCtx->sample_rate:%d ", pCodecCtx->sample_rate);  
  65.     #endif  
  66.     i = pCodecCtx->sample_rate;  
  67.     if (ioctl (fd, SNDCTL_DSP_SPEED, &i) == -1)  
  68.     {  
  69.         fprintf (stderr, "Set speed to %d failed:%s ", i,  
  70.              strerror (errno));  
  71.         return (-1);  
  72.     }  
  73.     if (i != pCodecCtx->sample_rate)  
  74.     {  
  75.         fprintf (stderr, "do not support speed %d,supported is %d ",  
  76.              pCodecCtx->sample_rate, i);  
  77.         return (-1);  
  78.     }  
  79.       
  80.     // set channels;  
  81.     i = pCodecCtx->channels;  
  82.     #ifdef AUDIO_DEBUG  
  83.     printf ("pCodecCtx->channels:%d ", pCodecCtx->channels);  
  84.     #endif  
  85.     if ((ioctl (fd, SNDCTL_DSP_CHANNELS, &i)) == -1)  
  86.     {  
  87.         fprintf (stderr, "Set Audio Channels %d failed:%s ", i,  
  88.              strerror (errno));  
  89.         return (-1);  
  90.     }  
  91.     if (i != pCodecCtx->channels)  
  92.     {  
  93.         fprintf (stderr, "do not support channel %d,supported %d ",  
  94.             pCodecCtx->channels, i);  
  95.         return (-1);  
  96.     }  
  97.     // set bit format;  
  98.     i = AFMT_S16_LE;  
  99.     if (ioctl (fd, SNDCTL_DSP_SETFMT, &i) == -1)  
  100.     {  
  101.         fprintf (stderr, "Set fmt to bit %d failed:%s ", i,  
  102.              strerror (errno));  
  103.         return (-1);  
  104.     }  
  105.     if (i != AFMT_S16_LE)  
  106.     {  
  107.         fprintf (stderr, "do not support bit %d, supported %d ",  
  108.              AFMT_S16_LE, i);  
  109.         return (-1);  
  110.     }  
  111.       
  112.     // set application buffer size;  
  113.     // i = (0x00032 << 16) + 0x000c;        // 32 4kb buffer;  
  114.     // ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &i);  
  115.     i = 1;  
  116.     ioctl (fd, SNDCTL_DSP_PROFILE, &i);  
  117.       
  118.     return 0;  
  119. }  
  120.  
  121. void close_file (int fd)  
  122. {  
  123.     // close the file pointed by file descriptor fd;  
  124.     close (fd);  
  125. }  
  126.  
  127. //------------------------------------------------------------------------------  
  128. // handle audio;  
  129.  
  130. void display_AVCodecContext(AVCodecContext *pCodecCtx){  
  131.     //  
  132.     #define STDOUT stderr  
  133.     fprintf(STDOUT, "pCodecCtx->bit_rate:%d ", pCodecCtx->bit_rate);  
  134.     fprintf(STDOUT, "pCodecCtx->sample_rate:%d ", pCodecCtx->sample_rate);  
  135.     fprintf(STDOUT, "pCodecCtx->channels:%d ", pCodecCtx->channels);  
  136.     fprintf(STDOUT, "pCodecCtx->frame_size:%d ", pCodecCtx->frame_size);  
  137.     fprintf(STDOUT, "pCodecCtx->frame_number:%d ", pCodecCtx->frame_number);  
  138.     fprintf(STDOUT, "pCodecCtx->delay:%d ", pCodecCtx->delay);  
  139.     fprintf(STDOUT, "pCodecCtx->frame_bits:%d ", pCodecCtx->frame_bits);  
  140. }  
  141.  
  142. // error if return -1;  
  143. // success if return 0;  
  144. // 这里要用到指向指针的指针,否则传不到值;  
  145. int av_init (char *file_name, AVFormatContext ** pFormatCtx,  
  146.     AVCodecContext ** pAudioCodecCtx, int *p_audioStream,   
  147.     AVCodecContext ** pVideoCodecCtx, int *p_videoStream)  
  148. {  
  149.     // init the codec and format of input file file_name;  
  150.     int audioStream, i;  
  151.     int videoStream;  
  152.     AVCodec *pAudioCodec;  
  153.     AVCodec *pVideoCodec;  
  154.     // catch error  
  155.     assert(file_name != NULL);  
  156.     assert(*pFormatCtx != NULL);  
  157.     assert(*pAudioCodecCtx != NULL);  
  158.       
  159.     // Register all formats and codecs  
  160.     av_register_all ();  
  161.       
  162.     // open file  
  163.     if (av_open_input_file (pFormatCtx, file_name, NULL, 0, NULL) != 0){  
  164.         // Couldn't open file  
  165.         fprintf (stderr, " Can't open %s! ", file_name);  
  166.         return -1;      
  167.     }  
  168.  
  169.     // Retrieve stream information  
  170.     if (av_find_stream_info (*pFormatCtx) < 0){  
  171.         // Couldn't find stream information  
  172.         return -1;      
  173.     }  
  174.       
  175.     #ifdef AV_DEBUG  
  176.     // Dump information about file onto standard error  
  177.     dump_format (*pFormatCtx, 0, file_name, false);  
  178.     #endif  
  179.       
  180.     // Find the first audio and video stream respectively  
  181.     audioStream = -1;  
  182.     videoStream = -1;  
  183.     for (i = 0; i < (*pFormatCtx)->nb_streams; i++){  
  184.         if ((*pFormatCtx)->streams[i]->codec->codec_type ==  
  185.             CODEC_TYPE_AUDIO)  
  186.         {  
  187.             audioStream = i;  
  188.         }else if ((*pFormatCtx)->streams[i]->codec->codec_type ==  
  189.             CODEC_TYPE_VIDEO){  
  190.             videoStream = i;  
  191.         }  
  192.     }  
  193.       
  194.     #ifdef AV_DEBUG  
  195.     // dump_stream_info(pFormatCtx);  
  196.     #endif  
  197.       
  198.     // exclude error  
  199.     if (audioStream == -1){  
  200.         // Didn't find a audio or video stream  
  201.         // return -1;      
  202.         printf("No Audio ");  
  203.     }  
  204.     if (videoStream == -1){  
  205.         // Didn't find a audio or video stream  
  206.         // return -1;      
  207.         printf("No Video ");  
  208.     }  
  209.  
  210.     // Get a pointer to the codec context for the audio stream  
  211.     *pAudioCodecCtx = (*pFormatCtx)->streams[audioStream]->codec;  
  212.     *pVideoCodecCtx = (*pFormatCtx)->streams[videoStream]->codec;  
  213.  
  214.     // Find the decoder for the audio stream  
  215.     pAudioCodec = avcodec_find_decoder ((*pAudioCodecCtx)->codec_id);  
  216.     pVideoCodec = avcodec_find_decoder ((*pVideoCodecCtx)->codec_id);  
  217.     //   
  218.     if (pAudioCodec == NULL){  
  219.         return -1;    // Codec not found  
  220.     }  
  221.     if (pVideoCodec == NULL){  
  222.         return -1;    // Codec not found  
  223.     }  
  224.  
  225.     // Open audio codec  
  226.     if (avcodec_open ((*pAudioCodecCtx), pAudioCodec) < 0){  
  227.         return -1;    // Could not open codec  
  228.     }  
  229.     // Open video codec  
  230.     if (avcodec_open ((*pVideoCodecCtx), pVideoCodec) < 0){  
  231.         return -1;    // Could not open codec  
  232.     }  
  233.       
  234.     #ifdef AUDIO_DEBUG  
  235.     // printf ("pCodecCtx->sample_rate:%d, audioStream:%d ", (*pCodecCtx)->sample_rate, audioStream);  
  236.     // display_AVCodecContext(*pCodecCtx);  
  237.     #endif  
  238.       
  239.     *p_audioStream = audioStream;  
  240.     *p_videoStream = videoStream;  
  241.       
  242.     return 0;  
  243. }  
  244.  
  245. void av_play (AVFormatContext * pFormatCtx,  
  246.     AVCodecContext * pAudioCodecCtx, int audioStream,   
  247.     AVCodecContext * pVideoCodecCtx, int videoStream)  
  248.     // AVCodecContext * pCodecCtx, int audioStream)  
  249. {  
  250.     // which was read from one frame;  
  251.     AVPacket packet;  
  252.     uint32_t len;  
  253.     uint8_t decompressed_audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];  
  254.     int decompressed_audio_buf_size;  
  255.     uint8_t * p_decompressed_audio_buf;  
  256.     int fd = -1;    // audio file or test file?  
  257.     char filename[64] = "/dev/dsp";  
  258.     int mode = O_WRONLY;  
  259.     // Video;  
  260.     AVFrame *pFrame;  
  261.     AVFrame *pFrameYUV;  
  262.     int frameFinished;  
  263.       
  264.     /**// SDL initialization  
  265.     SDL_Surface *screen =  
  266.     SDL_SetVideoMode (pVideoCodecCtx->width, pVideoCodecCtx->height, 0, SDL_HWSURFACE);  
  267.     SDL_Overlay *overlay =  
  268.     SDL_CreateYUVOverlay (pVideoCodecCtx->width, pVideoCodecCtx->height,  
  269.               SDL_YV12_OVERLAY,  
  270.               screen);  
  271.     static SDL_Rect rect;  
  272.     rect.x = 0;  
  273.     rect.y = 0;  
  274.     rect.w = pVideoCodecCtx->width;  
  275.     rect.h = pVideoCodecCtx->height;  
  276.     /**///  
  277.       
  278.     // open audio file or written file  
  279.     // printf("fd:%d", fd);  
  280.     fd = open_file(filename, mode);  
  281.     // printf("fd:%d", fd);  
  282.     //   
  283.     set_audio(fd, pAudioCodecCtx);  
  284.       
  285.     //  
  286.     printf("(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2=%d ", (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2);  
  287.     printf("AVCODEC_MAX_AUDIO_FRAME_SIZE=%d ", AVCODEC_MAX_AUDIO_FRAME_SIZE);  
  288.       
  289.     // for a test  
  290.     // char test_file[256] = "my_pcm.pcm";  
  291.     // fd = open_file(test_file, mode);  
  292.       
  293.     #ifdef AV_DEBUG  
  294.     static int size = 0;  
  295.     #endif  
  296.     //  
  297.       
  298.     // set the sched priority  
  299.     // 这是为了提高音频优先级;不晓得起作用没;  
  300.     int policy = SCHED_FIFO;  
  301.     sched_setscheduler(0, policy, NULL);  
  302.       
  303.     // Allocate video frame  
  304.     pFrame = avcodec_alloc_frame ();  
  305.     // Allocate an AVFrame structure  
  306.     pFrameYUV = avcodec_alloc_frame ();  
  307.     if (pFrameYUV == NULL)  
  308.         return;  
  309.       
  310.     // Set SDL events  
  311.     SDL_EventState (SDL_ACTIVEEVENT, SDL_IGNORE);  
  312.     SDL_EventState (SDL_MOUSEMOTION, SDL_IGNORE);  
  313.     // SDL_ShowCursor (SDL_ENABLE);  
  314.       
  315.     int write_buf_size = 4196;  
  316.     int written_size;  
  317.     while ((av_read_frame (pFormatCtx, &packet) >= 0)  
  318.         && (SDL_PollEvent (NULL) == 0))  
  319.     {  
  320.         // Is this a packet from the audio stream?  
  321.         // 判断是否音频帧;  
  322.         if (packet.stream_index == audioStream)  
  323.         {  
  324.             // Decode audio frame  
  325.             // 解码音频数据为pcm数据;  
  326.             len = avcodec_decode_audio (pAudioCodecCtx,    
  327.                             (int16_t *)decompressed_audio_buf,   
  328.                             &decompressed_audio_buf_size,        // it is the decompressed frame in BYTES 解码后的数据大小,字节为单位;  
  329.                             packet.data,   
  330.                             packet.size );  
  331.             // printf("len:%d, packet.size:%d ", len, packet.size);  
  332.             // printf("packet.pts:%d packet.dts:%d ", packet.pts, packet.dts);  
  333.             if ( len < 0 ){  
  334.                 // if error len = -1  
  335.                 printf("+----- error in decoding audio frame ");  
  336.                 // exit(0);  
  337.             }  
  338.             // audio_buf_info info;  
  339.             p_decompressed_audio_buf = decompressed_audio_buf;  
  340.             while ( decompressed_audio_buf_size > 0 ){  
  341.                 // 解码后数据不为零,则播放之,为零,则;  
  342.                 written_size = write(fd, p_decompressed_audio_buf, decompressed_audio_buf_size);  
  343.                 if ( written_size == -1 ){  
  344.                     // printf("error:decompressed_audio_buf_size:%d, decompressed_audio_buf_size:%d, %s ",   
  345.                                 decompressed_audio_buf_size, decompressed_audio_buf_size,strerror(errno));  
  346.                     // usleep(100);  
  347.                     continue;  
  348.                 }  
  349.                 // printf("decompressed_audio_buf_size:%d, written_size:%d ",   
  350.                             decompressed_audio_buf_size, written_size);  
  351.                 decompressed_audio_buf_size -= written_size;  
  352.                 p_decompressed_audio_buf += written_size;  
  353.             }// end while  
  354.         }  
  355.         else if (packet.stream_index == videoStream)  
  356.         {  
  357.             // Decode video frame  
  358.             avcodec_decode_video (pVideoCodecCtx, pFrame, &frameFinished,  
  359.                     packet.data, packet.size);  
  360.             // Did we get a video frame?  
  361.             if (frameFinished) {  
  362.             // Convert the image from its native format to YUV, and display  
  363.               
  364.             SDL_LockYUVOverlay (overlay);  
  365.             pFrameYUV->data[0] = overlay->pixels[0];  
  366.             pFrameYUV->data[1] = overlay->pixels[2];  
  367.             pFrameYUV->data[2] = overlay->pixels[1];  
  368.               
  369.             pFrameYUV->linesize[0] = overlay->pitches[0];  
  370.             pFrameYUV->linesize[1] = overlay->pitches[2];  
  371.             pFrameYUV->linesize[2] = overlay->pitches[1];  
  372.               
  373.             img_convert ((AVPicture *) pFrameYUV, PIX_FMT_YUV420P,   
  374.                         (AVPicture *) pFrame, pVideoCodecCtx->pix_fmt,   
  375.                         pVideoCodecCtx->width, pVideoCodecCtx->height);  
  376.             SDL_UnlockYUVOverlay (overlay);  
  377.             SDL_DisplayYUVOverlay (overlay, &rect);  
  378.             /**////  
  379.             // SDL_Delay (33);  
  380.             }  
  381.         }// end if  
  382.         // Free the packet that was allocated by av_read_frame  
  383.         av_free_packet (&packet);  
  384.     }// end while of reading one frame;  
  385.       
  386.     // Free the RGB image  
  387.     av_free (pFrameYUV);  
  388.     // Free the YUV frame  
  389.     av_free (pFrame);  
  390.     // for test lsosa  
  391.     // printf("size = %d ", size / 1024 / 1024 );  
  392.     SDL_FreeYUVOverlay (overlay);  
  393.       
  394.     close_file(fd);  
  395. }  
  396.  
  397. void av_close (AVFormatContext * pFormatCtx, AVCodecContext * pAudioCodecCtx,   
  398.     AVCodecContext * pVideoCodecCtx)  
  399. {  
  400.     // close the file and codec  
  401.     // Close the codec  
  402.     avcodec_close (pAudioCodecCtx);  
  403.     // Close the codec  
  404.     avcodec_close (pVideoCodecCtx);  
  405.  
  406.     // Close the video file  
  407.     av_close_input_file (pFormatCtx);  
  408. }  
  409.  
  410. //------------------------------------------------------------------------------  
  411.  
  412. int main (int argc, char **argv){  
  413.     //  
  414.     AVFormatContext *pFormatCtx;  
  415.     int audioStream = -1;  
  416.     int videoStream = -1;  
  417.     AVCodecContext *pAudioCodecCtx;  
  418.     AVCodecContext *pVideoCodecCtx;  
  419.       
  420.     // exclude the error about args;  
  421.     if ( argc != 2 ){  
  422.         printf("please give a file name ");  
  423.         exit(0);  
  424.     }  
  425.       
  426.     // 注意:这里要用到指向指针的指针,是因为这个初始化函数需要对指针的地址进行改动,  
  427.     // 所以,只有这么做,才能达到目的;  
  428.     if ( av_init(argv[1], &pFormatCtx, &pAudioCodecCtx, &audioStream, &pVideoCodecCtx, &videoStream) < 0 ){  
  429.         //  
  430.         fprintf(stderr, "error when av_init ");  
  431.     }  
  432.       
  433.     // play the audio file  
  434.     av_play(pFormatCtx, pAudioCodecCtx, audioStream, pVideoCodecCtx, videoStream);  
  435.       
  436.     // close all the opend files  
  437.     av_close(pFormatCtx, pAudioCodecCtx, pVideoCodecCtx);  
  438.       
  439. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值