使用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);

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值