SDL 与 FFMPEG 音乐播放器开发(4)——使用FFMPEG库解码

来源:互联网 发布:mac 固态硬盘windows10 编辑:程序博客网 时间:2024/06/05 06:27

首先说一下压缩这件事,压缩其实就是以一种更省空间的方法存储文件,甚至有时会为了省下空间而放弃某些文件信息。音频、视频、图片这三大媒体类文件,为了传输与存储的方便,压缩就必不可少,发展至今,可以说已经有一套比较标准的媒体文件格式,其中蕴含了不少先人的智慧,每一样都包涵了他们很长一段时间的努力。

如果要想精通他们的解析和转换,并不是什么简单的事。不过有时这并不是我们希望研究的方向,于是我们可以引用FFMPEG解码库,使用它的方法,可以解码大多主流音频格式,而不必深究每个文件格式(因为别人已经帮你研究好了)。


首先这里以在VS上开发为例,你首先要引用FFMPEG的LIB文件,在项目属性->配置属性->连接器->输入的附加依赖项中,加入你要链接的LIB文件。并在项目的头文件当中include其头文件。

#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"

然后就是库中方法的使用

<span style="white-space:pre"></span>AVFormatContext*pFormatCtx;int <span style="white-space:pre"></span>i, audioStream;AVCodecContext*pCodecCtx;AVCodec*pCodec;char url[300] = { 0 };strcpy(url, (const char*)filePath);//Register all available file formats and codecs
<span style="white-space: pre;"></span>av_register_all();
//init ,getcontextpFormatCtx = avformat_alloc_context();//有参数avdic//if(avformat_open_input(&pFormatCtx,url,NULL,&avdic)!=0){if (avformat_open_input(&pFormatCtx, url, NULL, NULL) != 0){printf("Couldn't open file.\n");return -1;}
// Retrieve stream informationif (av_find_stream_info(pFormatCtx) < 0){printf("Couldn't find stream information.\n");return -1;}// Dump valid information onto standard errorav_dump_format(pFormatCtx, 0, url, false);// Find the first audio streamaudioStream = -1;for (i = 0; i < pFormatCtx->nb_streams; i++)//原为codec_type==CODEC_TYPE_AUDIOif (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){audioStream = i;break;}if (audioStream == -1){printf("Didn't find a audio stream.\n");return -1;}// Get a pointer to the codec context for the audio streampCodecCtx = pFormatCtx->streams[audioStream]->codec;// Find the decoder for the audio streampCodec = avcodec_find_decoder(pCodecCtx->codec_id);if (pCodec == NULL){printf("Codec not found.\n");return -1;}// Open codecif (avcodec_open(pCodecCtx, pCodec) < 0){printf("Could not open codec.\n");return -1;}

以上是检测能否打开音频(其实视频也行)文件,并检查它是不是有信息。最后转存文件,并找到、打开解码器。然后我们得存储转码好的文件。

<span style="white-space:pre"></span>FILE *pFile;char buf[256];sprintf(buf, "output/%soutput.pcm", filePath);
if (fopen(buf, "rb+"))//如果output文件已经存在,说明音频文件已经进行过解码,返回0。{return 0;}
pFile = fopen(buf, "wb");//如果不存在就以创建并写入的形式打开
/*** Write audio into file ******///把结构体改为指针AVPacket *packet = (AVPacket *)malloc(sizeof(AVPacket));av_init_packet(packet);AVFrame*pFrame;pFrame = avcodec_alloc_frame();
</pre><pre name="code" class="cpp"><pre name="code" class="cpp"><span style="white-space:pre"></span>uint32_t ret, len = 0;int got_picture;while (av_read_frame(pFormatCtx, packet) >= 0){if (packet->stream_index == audioStream){//将packet读取为Frameret = avcodec_decode_audio4(pCodecCtx, pFrame,&got_picture, packet);if (ret < 0) // if error len = -1{printf("Error in decoding audio frame.\n");exit(0);}//写入output.pcmif (got_picture > 0){fwrite(pFrame->data[0], 1, pFrame->linesize[0], pFile);}}// Free the packet that was allocated by av_read_frame//已改av_free_packet(packet);}// Close filefclose(pFile);// Close the codecavcodec_close(pCodecCtx);// Close the video fileav_close_input_file(pFormatCtx);return 0;


新建输出文件,并将解码所得写入文件之中,最后关闭设备。解码完成,我们成功将音频文件输出为PCM文件。PCM文件播放相关代码我在前面几篇都有提及,总之进行解码之后就可以对PCM文件进行播放,当然,如果想边解码边播放,可以新建多个线程进行解码并播放,SDL也将Thread封装为SDL_Thread,使用起来较为简单,下一节我会说关于SDL_Thread的使用。


以及大家可以联系我125650971@qq.com

0 0