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

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

2011-06-03 16:26 295 查看
使用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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐