您的位置:首页 > 编程语言

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

2007-03-15 19:45 429 查看
 今天突发奇想,就在以前音频播放器(详细情况请看这里——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);


    


}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐