今天突发奇想,就在以前音频播放器(详细情况请看这里——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://www.rosoo.net/a/200912/8060.html