`
he91_com
  • 浏览: 399363 次
文章分类
社区版块
存档分类
最新评论

ffmpeg + sdl -03 简单音频播放器实现

 
阅读更多

没办法,工作中遇到了问题。


目前NEC EMMA的架构如下:

从USB读入文件 -> 文件分析并提取Packet中的Payload Data -> NEC HANDLE AVTransfer -> NEC HANDLE WMV -> AUDIO OUTPUT


按照驱动的API写好代码后却怎么也没有声音,所有API返回值均OK。

郁闷开始了。继续绝望中寻找希望。


为了对比调试,参考

http://blog.csdn.net/ashlingr/article/details/7791321


并做了一些ffmpeg版本升级修改。

修改前:

  1. len=avcodec_decode_audio(pAudioCodecCtx,
  2. (int16_t*)decompressed_audio_buf,
  3. &decompressed_audio_buf_size,//itisthedecompressedframeinBYTES解码后的数据大小,字节为单位;
  4. packet.data,
  5. packet.size);

修改后:

decompressed_audio_buf_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2; // 不加这一行,执行时会出错。

len = avcodec_decode_audio3 (pCodecCtx,

(int16_t *)decompressed_audio_buf,

&decompressed_audio_buf_size, // it is the decompressed frame in BYTES

&packet);


遇到的问题:

/dev/dsp 设备不存在

解决办法:

modprobe snd_pcm_oss (需要su到root用户)


完整代码如下:(基本来自http://bbs.chinavideo.org/viewthread.php?tid=1247&extra=page%3D1

#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>


#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!/n", 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/n", pCodecCtx->sample_rate);
#endif
i = pCodecCtx->sample_rate;
if (ioctl (fd, SNDCTL_DSP_SPEED, &i) == -1)
{
fprintf (stderr, "Set speed to %d failed:%s/n", i,
strerror (errno));
return (-1);
}
if (i != pCodecCtx->sample_rate)
{
fprintf (stderr, "do not support speed %d,supported is %d/n",
pCodecCtx->sample_rate, i);
return (-1);
}

// set channels;
i = pCodecCtx->channels;
#ifdef AUDIO_DEBUG
printf ("pCodecCtx->channels:%d/n", pCodecCtx->channels);
#endif
if ((ioctl (fd, SNDCTL_DSP_CHANNELS, &i)) == -1)
{
fprintf (stderr, "Set Audio Channels %d failed:%s/n", i,
strerror (errno));
return (-1);
}
if (i != pCodecCtx->channels)
{
fprintf (stderr, "do not support channel %d,supported %d/n",
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/n", i,
strerror (errno));
return (-1);
}
if (i != AFMT_S16_LE)
{
fprintf (stderr, "do not support bit %d, supported %d/n",
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/n", pCodecCtx->bit_rate);
fprintf(STDOUT, "pCodecCtx->sample_rate:%d/n", pCodecCtx->sample_rate);
fprintf(STDOUT, "pCodecCtx->channels:%d/n", pCodecCtx->channels);
fprintf(STDOUT, "pCodecCtx->frame_size:%d/n", pCodecCtx->frame_size);
fprintf(STDOUT, "pCodecCtx->frame_number:%d/n", pCodecCtx->frame_number);
fprintf(STDOUT, "pCodecCtx->delay:%d/n", pCodecCtx->delay);
fprintf(STDOUT, "pCodecCtx->frame_bits:%d/n", pCodecCtx->frame_bits);
}


// error if return -1;
// success if return 0;
// 这里要用到指向指针的指针,否则传不到值;
int av_init (char *file_name, AVFormatContext ** pFormatCtx,
AVCodecContext ** pCodecCtx, int *p_audioStream)
{
// init the codec and format of input file file_name;
int audioStream, i;
AVCodec *pCodec;
// catch error
assert(file_name != NULL);
assert(*pFormatCtx != NULL);
assert(*pCodecCtx != 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!/n", 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, 0);
#endif

// Find the first audio and video stream respectively
audioStream = -1;
for (i = 0; i < (*pFormatCtx)->nb_streams; i++){
if ((*pFormatCtx)->streams[i]->codec->codec_type ==
AVMEDIA_TYPE_AUDIO)
{
audioStream = i;
}
}

#ifdef AV_DEBUG
// dump_stream_info(pFormatCtx);
#endif

// exclude error
if (audioStream == -1){
// Didn't find a audio or video stream
return -1;
}


// Get a pointer to the codec context for the audio stream
*pCodecCtx = (*pFormatCtx)->streams[audioStream]->codec;


// Find the decoder for the audio stream
pCodec = avcodec_find_decoder ((*pCodecCtx)->codec_id);
if (pCodec == NULL)
return -1; // Codec not found


// Open codec
if (avcodec_open ((*pCodecCtx), pCodec) < 0){
return -1; // Could not open codec
}

#ifdef AUDIO_DEBUG
// printf ("pCodecCtx->sample_rate:%d, audioStream:%d/n", (*pCodecCtx)->sample_rate, audioStream);
// display_AVCodecContext(*pCodecCtx);
#endif

*p_audioStream = audioStream;

return 0;
}


void av_play (AVFormatContext * pFormatCtx,
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;
//

// open audio file or written file
// printf("fd:%d", fd);
fd = open_file(filename, mode);
printf("fd:%d \n", fd);
//
set_audio(fd, pCodecCtx);

//
printf("(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2=%d\n", (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2);
printf("AVCODEC_MAX_AUDIO_FRAME_SIZE=%d\n", 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);

int write_buf_size = 4196;
int written_size;
while (av_read_frame (pFormatCtx, &packet) >= 0)
{
// Is this a packet from the audio stream?
// 判断是否音频帧;
if (packet.stream_index == audioStream)
{
// Decode audio frame
// 解码音频数据为pcm数据;
decompressed_audio_buf_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2;
len = avcodec_decode_audio3 (pCodecCtx,
(int16_t *)decompressed_audio_buf,
&decompressed_audio_buf_size, // it is the decompressed frame in BYTES
&packet);
// printf("len:%d, packet.size:%d/n", len, packet.size);
if ( len < 0 ){
// if error len = -1
printf("+----- error in decoding audio frame\n");
// exit(0);
}
// test lsosa


// printf("size = %d/n", size);
//******************************************************************
// 重点是这一部分,使用oss播放的代码,之前的数据写是否完整的问题就是出在这里,或者是前面的set_audio函数设置不正确;
// 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/n", /
// decompressed_audio_buf_size, decompressed_audio_buf_size,strerror(errno));
// usleep(100);
continue;
}
// printf("decompressed_audio_buf_size:%d, written_size:%d/n", /
// decompressed_audio_buf_size, written_size);
decompressed_audio_buf_size -= written_size;
p_decompressed_audio_buf += written_size;

}// end while
//******************************************************************
}
else
{
printf("+----- this is not audio frame/n");
}// end if
// Free the packet that was allocated by av_read_frame
av_free_packet (&packet);
}// end while of reading one frame;

close_file(fd);
}


void av_close (AVFormatContext * pFormatCtx, AVCodecContext * pCodecCtx)
{
// close the file and codec


// Close the codec
avcodec_close (pCodecCtx);


// Close the video file
av_close_input_file (pFormatCtx);
}


//------------------------------------------------------------------------------


int main (int argc, char **argv){
//
AVFormatContext *pFormatCtx;
int audioStream = -1;
AVCodecContext *pCodecCtx;

// exclude the error about args;
if ( argc != 2 ){
printf("please give a file name\n");
exit(0);
}

// 注意:这里要用到指向指针的指针,是因为这个初始化函数需要对指针的地址进行改动,
// 所以,只有这么做,才能达到目的;
if ( av_init(argv[1], &pFormatCtx, &pCodecCtx, &audioStream) < 0 ){
//
fprintf(stderr, "error when av_init\n");
}

// play the audio file
av_play(pFormatCtx, pCodecCtx, audioStream);

// close all the opend files
av_close(pFormatCtx, pCodecCtx);

}

分享到:
评论

相关推荐

    ffmpeg+SDL2实现的音频播放器V2.0(无杂音)

    在这个"ffmpeg+SDL2实现的音频播放器V2.0(无杂音)"项目中,开发者利用 FFmpeg 的音频解码功能和 SDL2 的音频播放能力构建了一个高质量的音频播放器。以下是这个项目中涉及的主要知识点: 1. **FFmpeg 音频解码**...

    ffmpeg+SDL2实现的视频播放器(windows版)

    本项目结合 FFmpeg 和 SDL2 实现了一个简单的视频播放器,特别针对 Windows 平台进行了优化。 在 Windows 上使用 Visual Studio(VS2010 或 VS2015)进行开发时,首先需要安装 FFmpeg 和 SDL2 的开发库。确保下载的...

    Qt+FFMPEG+SDL实现的视频播放器

    **Qt+FFMPEG+SDL实现的视频播放器** 在软件开发中,创建一个功能完备的视频播放器是一项挑战,但结合Qt、FFmpeg和SDL(Simple DirectMedia Layer)库,我们可以构建出一个高效且跨平台的解决方案。下面将详细阐述这...

    基于FFMPEG+SDL2播放音频

    基于FFMPEG+SDL2写的播放mp3文件程序,采用链表队列的方式来传递数据,详细解释见博文《基于FFMPEG+SDL2播放音频》,链接:https://blog.csdn.net/u011003120/article/details/81950045

    ffmpeg+sdl视音频播放器

    ffmpeg+sdl播放器解码视音频,使用ffmpeg-2.5.2+SDL-1.2.15,参考ffmpeg官方例子,欢迎交流 内含10个工程 1.保存为bmp图片 2.解码视频 3.解码视频, 音频 4.分离代码,加入线程(伪同步) 5.视频同步到音频 6.音频同步到...

    QT + ffmpeg + sdl音频播放器

    QT + ffmpeg + SDL音频播放器是一种利用开源库组合来实现音频播放的应用程序。在这个项目中,QT是一个跨平台的C++应用程序开发框架,用于构建用户界面;ffmpeg是一个强大的多媒体处理库,负责音频和视频的解码;而...

    基于C++ Qt+FFMPEG+SDL2写的视频播放器源代码,可以播放本地视频

    在本文中,我们将深入探讨如何使用C++、Qt、FFmpeg和SDL2库来构建一个本地视频播放器。首先,让我们分别了解这些组件的核心概念。 **Qt** 是一个跨平台的应用程序开发框架,广泛用于创建GUI(图形用户界面)应用...

    最简单的基于FFMPEG+SDL的音频播放器

    FFMPEG工程浩大,可以参考的书籍又不是很多,因此很多刚学习FFMPEG的人常常感觉到无从下手。...该播放器虽然简单,但是几乎包含了使用FFMPEG播放一个音频所有必备的API,并且使用SDL播放解码出来的音频。

    ffmpeg+sdl视频播放器

    此外,项目中包含的"video_player"可能是一个源代码文件或者整个项目文件夹,里面包含了实现这个FFmpeg+SDL视频播放器的所有源代码、配置文件和其他相关资源。用户可以通过查看这些文件,了解如何将FFmpeg与SDL结合...

    最简单的FFMPEG+SDL播放器

    "最简单的FFMPEG+SDL播放器"项目,就是结合这两个强大的库,构建了一个基础的媒体播放器。对于初学者来说,这个项目具有极高的学习价值。通过阅读和理解代码,你可以了解如何使用FFmpeg进行音频和视频的解码,以及...

    ffmpeg+sdl2视音频播放器

    ffmpeg+sdl2播放器解码视音频,使用ffmpeg-2.5.2+SDL2-2.0.3,如有bug或建议,欢迎交流 内含5个工程 1.保存为bmp图片 2.解码视频 3.解码视音频 4.分离代码,加入线程(伪同步) 5.视音频同步,快进快退功能,播放/暂停...

    qt使用FFmPeg+SDL2.0+QOpenGLWidget实现的音视频播放器,支持播放器的多数基本功能

    qt使用FFmPeg+SDL2.0+QOpenGLWidget实现的视频播放器,FFmPeg+SDL2.0解码音视频,视频图像解码为YUV420的格式,然后使用QOpenGLWidget进行显示。亲测在windows和Linux下都可使用,附带FFmPeg+SDL2.0第三方库 支持...

    最简单的基于FFMPEG+SDL的音频播放器 2 (修正)

    因此我把自己做项目过程中实现的一个非常简单的音频播放器(大约200-300行代码)源代码传上来,以作备忘,同时方便新手学习FFMPEG。 该播放器虽然简单,但是几乎包含了使用FFMPEG播放一个音频所有必备的API,并且...

    ffmpeg2.6+sdl2.0音视频同步简单播放器(同步需要更改和优化)

    vs2013工程,基于最新的ffmpeg2.6 和 SDL2.0 开发的简单音视频播放器,同步问题有待大改动,参考:http://www.cnblogs.com/Bonker/p/3998836.html

    基于Qt+FFmpeg设计的视频播放器(SDL输出音频)

    【标题】"基于Qt+FFmpeg设计的视频播放器(SDL输出音频)"的实现与解析 在数字媒体领域,开发一个跨平台的视频播放器是一项常见的任务。本项目使用了Qt库作为用户界面框架,结合FFmpeg进行视频解码,并利用SDL2.0处理...

    ffmpeg+SDL2.0简单是视频播放器

    在这个"ffmpeg+SDL2.0简单视频播放器"项目中,开发者通过结合这两个库,创建了一个基本的本地视频播放器。 FFmpeg库包含了多种功能,如视频解码、音频解码、格式转换、流媒体处理等。它的核心组件包括libavcodec...

    最简单的基于FFMPEG+SDL的音频播放器 2

    因此我把自己做项目过程中实现的一个非常简单的音频播放器(大约200-300行代码)源代码传上来,以作备忘,同时方便新手学习FFMPEG。 该播放器虽然简单,但是几乎包含了使用FFMPEG播放一个音频所有必备的API,并且...

    基于Qt+FFmpeg+SDL实现的音视频播放器.zip

    在我们的播放器中,SDL将帮助我们实现视频的显示和音频的播放。 在实际开发过程中,我们需要做以下几步: 1. **初始化环境**:安装Qt、FFmpeg和SDL的开发库,并在项目中配置相应的头文件和库路径。 2. **设计UI**...

    基于FFmpeg+SDL的视频播放器_其它文档

    FFmpeg是一个强大的跨平台的音频和视频处理工具集,而SDL(Simple DirectMedia Layer)是一个用于创建跨平台多媒体应用的库。在这个“基于FFmpeg+SDL的视频播放器”项目中,它们被结合起来构建了一个基本的视频...

    FFmpeg+SDL的视频播放器资料

    FFmpeg+SDL的视频播放器资料: (0) 大纲 (1) 视音频基础知识 (2) FFmpeg命令行工具的使用 (3) FFmpeg视频解码器 (4) SDL视频显示 (5) FFmpeg+SDL视频播放器 (6) FFmpeg+SDL视频播放器-图形界面版

Global site tag (gtag.js) - Google Analytics