使用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
今天突发奇想,就在以前音频播放器(详细情况请看这里——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
相关文章推荐
- 使用ffmpeg为库编写的小型多媒体播放器源代码
- 一个使用JAVA编写的类似按键精灵的程序,支持脚本文件编写(含源代码)
- 3.第三单元任务二实训:使用作业提交系统提交Java作业时 ,需要输入Java源代码文件名和自己的邮箱,提交前对Java文件名以及邮箱进行有效检查。编写程序实现对输入的Java源文件名以及邮箱有效性的
- 一个使用JAVA编写的类似按键精灵的程序,支持脚本文件编写(含源代码)
- 一个使用JAVA编写的类似按键精灵的程序,支持脚本文件编写(含源代码)
- 使用soaoffice中间件+asp实例编写小型的企业管理程序(一)
- 一个使用JAVA编写的类似按键精灵的程序,支持脚本文件编写(含源代码)
- 使用soaoffice中间件+asp实例编写小型的企业管理程序(二)
- 12、ffmpeg笔记-使用Android Studio编写第一个ffmpeg程序
- 如何使用AsyncSocket编写一个非常小型的群聊系统
- 一个使用JAVA编写的类似按键精灵的程序,支持脚本文件编写(含源代码)
- 使用FFmpeg编写音乐播放器
- 一个使用JAVA编写的类似按键精灵的程序,支持脚本文件编写(含源代码)
- 一个使用JAVA编写的类似按键精灵的程序,支持脚本文件编写(含源代码)
- 如何在VB 6.0 sp6 中使用WindowsMediaPlayer控件?编写一个属于自己的多媒体播放器?
- 图文并茂——使用xfire编写webservice,并通过C#调用
- IOS 编译ffmpeg For SDK6.1,模拟器、armv7、armv7s均可使用
- MacOS10.8.3+Xcode4.6+IOS6.1 编译FFmpeg,简单使用
- 编译在ios4.3中使用的ffmpeg库
- Oracle Database 10g 内幕:使用正规表达式编写更好的 SQL