您的位置:首页 > 产品设计 > 产品经理

FFMPEG解复用、解码测试,音频保存WAV文件,视频保存为PPM图像

2011-10-27 02:17 1391 查看

1.WAV(PCM)文件格式分析

WAVE文件作为多媒体中使用的声波文件格式之一,它是以RIFF格式为标准的。RIFF是英文ResourceInterchangeFileFormat的缩写,每个WAVE文件的头四个字节便是“RIFF”。WAVE文件由文件头和数据体两大部分组成。其中文件头又分为RIFF/WAV文件标识段和声音数据格式说明段两部分。WAVE文件各部分内容及格式见附表。  常见的声音文件主要有两种,分别对应于单声道(11.025KHz采样率、8Bit的采样值)和双声道(44.1KHz采样率、16Bit的采样值)。采样率是指:声音信号在“模→数”转换过程中单位时间内采样的次数。采样值是指每一次采样周期内声音模拟信号的积分值。  对于单声道声音文件,采样数据为八位的短整数(shortint00H-FFH);而对于双声道立体声声音文件,每次采样数据为一个16位的整数(int),高八位和低八位分别代表左右两个声道。   WAVE文件数据块包含以脉冲编码调制(PCM)格式表示的样本。WAVE文件是由样本组织而成的。   在单声道WAVE文件中,声道0代表左声道,声道1代表右声道。在多声道WAVE文件中,样本是交替出现的。  WAVE文件格式说明表    偏移地址  字节数  数据类型     内容   文件头  00H        4      char      "RIFF"标志  04H        4     longint     文件长度  08H        4      char       "WAVE"标志  0CH       4      char       "fmt"标志  10H       4               过渡字节(不定)  14H       2      int        格式类别(10H为PCM形式的声音数据)  16H       2      int        通道数,单声道为1,双声道为2  18H       2      int        采样率(每秒样本数),表示每个通道的播放速度,  1CH       4     longint      波形音频数据传送速率,其值为通道数×每秒数据位数×每 样本的数据位数/8。播放软件利用此值可以估计缓冲区的大小。  20H       2       int       数据块的调整数(按字节算的),其值为通道数×每样本的数据位值/8。播放软件需要一次处理多个该值大小的字节数据,以便将其值用于缓冲区的调整。  22H       2               每样本的数据位数,表示每个声道中各个样本的数据位数。如果有多个声道,对每个声道而言,样本大小都一样。  24H       4     char        数据标记符"data"  28H       4    longint      语音数据的长度  PCM数据的存放方式:  样本1样本2  8位单声道0声道0声道  8位立体声0声道(左)1声道(右)0声道(左)1声道(右)  16位单声道0声道低字节0声道高字节0声道低字节0声道高字节  16位立体声0声道(左)低字节0声道(左)高字节1声道(右)低字节1声道(右)高字节  WAVE文件的每个样本值包含在一个整数i中,i的长度为容纳指定样本长度所需的最小字节数。首先存储低有效字节,表示样本幅度的位放在i的高有效位上,剩下的位置为0,这样8位和16位的PCM波形样本的数据格式如下所示。   样本大小   数据格式        最大值   最小值  8位PCM     unsignedint     225     0  16位PCM    int            32767  -327672. FFMPEG解复用、解码测试,保存WAV音频文件和PPM图像文件,字幕的处理与保存未做完。代码如下:
/*************************************************************************************
**Notice:Copyright(c)2011AVITCorporation-AllRightsReserved
**
**Name:example.c
**
**Author:TangQi
**
**Date:2011-08-02
**
**Version:1.0
**
**Description:TheexampleisuseffmepgtoDemuxVideoFiles.Wecanprovetheresult
**ofdemuxisright.
**
**History:2011-08-02TangQiCreated
**
*************************************************************************************/
#include<libavcodec/avcodec.h>
#include<libavformat/avformat.h>
#include<libswscale/swscale.h>
#include<stdio.h>
#include<pthread.h>
/*Maybefollowheaderfiledon'tneed*/
#include<stdlib.h>
#include<time.h>
#defineMAX_SAVE_FRAME40
#defineMAX_AUDIO_BUF20000000
/*定义全局变量*/
pthread_mutex_tmutex;
pthread_cond_tcond;
intquit=0;
/*DefineDWORDandWORD*/
typedefunsignedlongDWORD;/*4Bytes*/
typedefunsignedshortWORD;/*2Bytes*/
/*Thestructofwaveheader*/
/*-------------------------*/
typedefstructRIFF_HEADER{
charavit_szRiffID[4];/*char="RIFF"*/
DWORDavit_dwRiffSize;/*filesize-8*/
charavit_szRiffFormat[4];/*char="WAVE"*/
}RIFF_HEADER;
typedefstructWAVE_FORMAT{
charavit_szWaveID[4];/*char="fmt"*/
DWORDavit_dwFSize;/*过渡字节Ox10*/
WORDavit_wFormaTag;/*编码格式,包括WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM等*/
WORDavit_wChannels;/*声道数,单声道为1,双声道为2*/
DWORDavit_dwSamplesPerSec;/*采样频率*/
DWORDavit_dwAvgBytesPerSec;/*每秒的数据量*/
WORDavit_wBlockAlign;/*块对齐*/
WORDavit_wBitsPerSample;/*WAVE文件的采样大小*/
//WORDsbSize;/*PCM中忽略此值*/
}WAVE_FORMAT;
typedefstructDATA_BLOCK{
charavit_szDataID[4];/*char="data"*/
DWORDavit_dwDataSize;/*datasize=filesize-44*/
}DATA_BLOCK;
/*ThestructofPacketQueueisusedtosavepacket.*/
/*-------------------------------------------------*/
typedefstructPacketQueue{
AVPacketList*first_pkt,*last_pkt;
intnb_packets;
intsize;
}PacketQueue;
/*defineaudioandvideoPacketQueue*/
PacketQueueaudioq;
PacketQueuevideoq;
PacketQueuesubtitleq;
/*Thehandleofpacketqueue*/
/*--------------------------*/
voidpacket_queue_init(PacketQueue*q)
{
memset(q,0,sizeof(PacketQueue));
pthread_mutex_init(&mutex,NULL);//createmutex
pthread_cond_init(&cond,PTHREAD_PROCESS_PRIVATE);//createcond
}
intpacket_queue_put(PacketQueue*q,AVPacket*pkt)
{
AVPacketList*pkt1;
if(av_dup_packet(pkt)<0){
return-1;
}
pkt1=av_malloc(sizeof(AVPacketList));
if(!pkt1)
return-1;
pkt1->pkt=*pkt;
pkt1->next=NULL;
pthread_mutex_lock(&mutex);
if(!q->last_pkt)
q->first_pkt=pkt1;
else
q->last_pkt->next=pkt1;
q->last_pkt=pkt1;
q->nb_packets++;
q->size+=pkt1->pkt.size;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
return0;
}
staticintpacket_queue_get(PacketQueue*q,AVPacket*pkt,intblock)
{
AVPacketList*pkt1;
intret;
pthread_mutex_lock(&mutex);
for(;;){
if(quit){
ret=-1;
break;
}
pkt1=q->first_pkt;
if(pkt1){
q->first_pkt=pkt1->next;
if(!q->first_pkt)
q->last_pkt=NULL;
q->nb_packets--;
q->size-=pkt1->pkt.size;
*pkt=pkt1->pkt;
av_free(pkt1);
ret=1;
break;
}elseif(!block){
ret=0;
break;
}else{
pthread_cond_signal(&cond);
}
}
pthread_mutex_unlock(&mutex);
returnret;
}
voidsave_video_frame(AVFrame*pFrame,intwidth,intheight,intiFrame)
{
FILE*frameFile;
charszFilename[32];
inth;
/*Createfilenameandopenfile*/
sprintf(szFilename,"frame%d.ppm",iFrame);
frameFile=fopen(szFilename,"wb");
if(frameFile==NULL)
return;
/*WriteframeFileheader*/
fprintf(frameFile,"P6\n%d%d\n255\n",width,height);
/*Writepixeldata*/
for(h=0;h<height;h++)
fwrite(pFrame->data[0]+h*pFrame->linesize[0],1,width*3,frameFile);
/*ClosetheframeFile*/
fclose(frameFile);
return;
}
voidvideo_thread(AVCodecContext*pCodecCtx)
{
AVPacketpkt1,*packet=&pkt1;
intlen1,frameFlag,numBytes,i;
AVFrame*pFrame,*pFrameRGB;
uint8_t*buffer;
printf("EC:video_threadIn\n");
i=0;
pFrame=avcodec_alloc_frame();
/*AllocbuffertopFrameRGB*/
if((pFrameRGB=avcodec_alloc_frame())==NULL)
return;
/*Determinerequiredbuffersizeandallocatebuffer*/
numBytes=avpicture_get_size(PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);
buffer=(uint8_t*)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill((AVPicture*)pFrameRGB,buffer,PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);
for(;;){
if(packet_queue_get(&videoq,packet,1)<0){
break;//quitgettingpackets
}
/*Decodevideoframe*/
len1=avcodec_decode_video2(pCodecCtx,pFrame,&frameFlag,packet);
/*Didwegetavideoframe?*/
if(frameFlag){
/*ConverttheimagefromitsnativeformattoRGB*/
structSwsContext*img_convert_ctx;
img_convert_ctx=sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,
pCodecCtx->width,pCodecCtx->height,PIX_FMT_RGB24,
SWS_BICUBIC,NULL,NULL,NULL);
sws_scale(img_convert_ctx,pFrame->data,pFrame->linesize,0,
pCodecCtx->height,pFrame->data,pFrameRGB->linesize);
/*Savetheframetodisk*/
if(++i<=MAX_SAVE_FRAME)
save_video_frame(pFrameRGB,pCodecCtx->width,pCodecCtx->height,i);
}
av_free_packet(packet);
}
av_free(buffer);
av_free(pFrameRGB);
av_free(pFrame);
return;
}
voidwrite_wave_header(AVCodecContext*aCodecCtx,FILE*pFile,intfilesize)
{
/*AddHeaderintothefilewhichisfilluppcmdata,andmakethisfilecanplay*/
/*Writeheaderfromthebeginningoffile*/
fseek(pFile,0,SEEK_SET);
RIFF_HEADERriffHeader;
memcpy(riffHeader.avit_szRiffID,"RIFF",4);//1-4byte
riffHeader.avit_dwRiffSize=filesize-8;
memcpy(riffHeader.avit_szRiffFormat,"WAVE",4);
fwrite(&riffHeader,1,sizeof(riffHeader),pFile);
/*Writewaveformat*/
WAVE_FORMATwaveFormat;
aCodecCtx->bits_per_coded_sample=16;/*这个值未找到,AVCodecContext中没有。需自己定义?*/
memcpy(waveFormat.avit_szWaveID,"fmt",4);
waveFormat.avit_dwFSize=0x10;
waveFormat.avit_wFormaTag=1;
waveFormat.avit_wChannels=aCodecCtx->channels;
waveFormat.avit_dwSamplesPerSec=aCodecCtx->sample_rate;/*44100、22050、48000HZ*/
waveFormat.avit_wBlockAlign=(aCodecCtx->bits_per_coded_sample)/8*waveFormat.avit_wChannels;
waveFormat.avit_dwAvgBytesPerSec=waveFormat.avit_dwSamplesPerSec*waveFormat.avit_wBlockAlign;
waveFormat.avit_wBitsPerSample=aCodecCtx->bits_per_coded_sample;
fwrite(&waveFormat,1,sizeof(waveFormat),pFile);
printf("channels=%d,sample_rate=%d,BlockAlign=%d,BytesPerSec=%d,BitsPerSample=%d\n",
waveFormat.avit_wChannels,waveFormat.avit_dwSamplesPerSec,waveFormat.avit_wBlockAlign,
waveFormat.avit_dwAvgBytesPerSec,waveFormat.avit_wBitsPerSample);
/*DataBlock*/
DATA_BLOCKdatablock;
memcpy(datablock.avit_szDataID,"data",4);
datablock.avit_dwDataSize=filesize-44;//41-44byte,calculated
fwrite(&datablock,1,sizeof(datablock),pFile);
printf("EC:audio_thread(),THelenofthePCMFileis%d,Endoftheaudio_decode\n",filesize);
fclose(pFile);
return;
}
/*ReadpacketfromPakcetQueue,anddecodeaudiodata*/
intaudio_decode_frame(AVCodecContext*aCodecCtx,uint8_t*audio_buf,intbuf_size)
{
staticAVPacketpkt,pkt_temp;
staticuint8_t*audio_pkt_data=NULL;
staticintaudio_pkt_size=0;
intlen1,data_size;
for(;;){
while(pkt_temp.size>0){
data_size=buf_size;
len1=avcodec_decode_audio3(aCodecCtx,(int16_t*)audio_buf,&data_size,&pkt_temp);/*avcodec_decode_audio2()tooold,changetoavcodec_decode_audio3()*/
if(len1<0){
/*iferror,skipthisframe*/
pkt_temp.size=0;
break;
}
pkt_temp.data+=len1;
pkt_temp.size-=len1;
if(data_size<=0){
/*Nodatayet,getmoreframes*/
continue;
}
/*Wehavedata,returnitandcomebackformorelater*/
returndata_size;
}
/*freethecurrentpacket*/
if(pkt.data)
av_free_packet(&pkt);
/*
if(quit){
return-1;
}*/
/*readnextpacketfromaudioPacketQueue*/
if(packet_queue_get(&audioq,&pkt,1)<0){
return-1;
}
pkt_temp.data=pkt.data;
pkt_temp.size=pkt.size;
}
}
voidaudio_thread(AVCodecContext*aCodecCtx)
{
intlen1,audio_size,len,ture,filesize,n;
staticuint8_taudio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE*3)/2];
staticunsignedintaudio_buf_size=0;
staticunsignedintaudio_buf_index=0;
len=MAX_AUDIO_BUF;
n=1;
/*CreatandopenaFile*/
FILE*pFile;
charfilename[32];
sprintf(filename,"test%d.wav",n);
pFile=fopen(filename,"wb");
/*AT44bytespointer,writedatatopFile*/
fseek(pFile,44,SEEK_SET);
filesize=44;
//ture=1;
/*decodeaudioframe*/
while(len>0){
if(audio_buf_index>=audio_buf_size){
/*Wehavealreadysentallourdata;getmore*/
audio_size=audio_decode_frame(aCodecCtx,audio_buf,sizeof(audio_buf));
/*Saveaudio_buftothePCMFile.*/
if(audio_size>0){
	fwrite(audio_buf,1,audio_size,pFile);
	filesize+=audio_size;
	printf("EC:audio_thread()THelenofthePCMFileis%d\n",filesize);
}
if(audio_size<0){
	/*Iferror,outputsilence*/
	audio_buf_size=1024;//arbitrary?
	memset(audio_buf,0,audio_buf_size);
	printf("EC:audio_thread()*****Outputsilence*****\n");
}else{
	audio_buf_size=audio_size;
}
audio_buf_index=0;
}
len1=audio_buf_size-audio_buf_index;
if(len1>len)
len1=len;
printf("EC:audio_thread(),audio_size=%d,audio_buf_size=%d,audio_buf_index=%d,len=%d,len1=%d\n",
	audio_size,audio_buf_size,audio_buf_index,len,len1);
//memcpy(stream,(uint8_t*)audio_buf+audio_buf_index,len1);
//stream+=len1;
len-=len1;
c241audio_buf_index+=len1;
}
/*writewaveheadertothisfile*/
write_wave_header(aCodecCtx,pFile,filesize);
return;
}
voidsubtitle_thread(AVCodecContext*sCodecCtx)
{
SubPicture*sp;
AVPacketpkt1,*pkt=&pkt1;
intlen1,got_subtitle;
inti;
FILE*textFile;
charfilename[32];
inttext_id=1;
sprintf(filename,"subtitle%d.txt",text_id);
textFile=fopen(filename,"wb");
for(;;){
if(packet_queue_get(&subtitleq,pkt,1)<0)
break;
len1=avcodec_decode_subtitle2(sCodecCtx,&sp->sub,&got_subtitle,pkt);
if(got_subtitle&&len1>0){
printf("EC:subtitle_thread()sub.format=%d,len1=%d\n",sp->sub.format,len1);
for(i=0;i<sp->sub.num_rects;i++){
switch(sp->sub.rects[i]->type){
caseSUBTITLE_TEXT:
printf("EC:subtitle()EnterinsaveSUBTITLE_TEXT\n");
fwrite(sp->sub.rects[i]->text,1,sizeof(sp->sub.rects[i]->text),textFile);
break;
caseSUBTITLE_ASS:
printf("EC:subtitle()EnterinsaveSUBTITLE_ASS\n");
break;
caseSUBTITLE_BITMAP:
printf("EC:subtitle()EnterinsaveSUBTITLE_BITMAP\n");
break;
default:
printf("EC:subtitle()EnterinsaveSUBTITLE_NONE\n");
break;
}
}
}
av_free_packet(pkt);
}
return;
}
voidavit_decode(AVFormatContext*pFormatCtx,AVCodecContext*pCodecCtx,
AVCodecContext*aCodecCtx,AVCodecContext*sCodecCtx,intsubtitle_flag)
{
pthread_taudio_id;
pthread_tvideo_id;
pthread_tsubtitle_id;
/*Createvideodecodethread*/
if(pthread_create(&video_id,NULL,(void*)video_thread,pCodecCtx)!=0)
printf("Createvideothreadfailure!\n");
/*Createaudiodecodethread*/
if(pthread_create(&audio_id,NULL,(void*)audio_thread,aCodecCtx)!=0)
printf("Createaudiothreadfailure!\n");
/*Createsubtitledecodethread*/
if(subtitle_flag!=-1){
if(pthread_create(&subtitle_id,NULL,(void*)subtitle_thread,sCodecCtx)!=0)
printf("Createsubtitlethreadfailure!\n");
}
return;
}
intmain(intargc,char*argv[])
{
inti,videoStream,audioStream,subtitleStream,frameFinished;
AVFormatContext*pFormatCtx;
AVCodecContext*pCodecCtx,*aCodecCtx,*sCodecCtx;
AVCodec*pCodec,*aCodec,*sCodec;
AVPacketpacket;
if(argc<2){
fprintf(stderr,"Usage:test<file>\n");
exit(1);
}
/*Registerallformatsandcodecs*/
av_register_all();
/*InitaudioPacketQueueandvideoPacketQueue.*/
packet_queue_init(&audioq);
packet_queue_init(&videoq);
packet_queue_init(&subtitleq)
/*Openvideofile*/
if(av_open_input_file(&pFormatCtx,argv[1],NULL,0,NULL)!=0){
printf("Couldn'topenthisfile,Pleaseprovideanotherone!\n");
return-1;//Couldn'topenthisfile
}
/*Findstreaminformation*/
if(av_find_stream_info(pFormatCtx)<0){
printf("Couldn'tfindstreaminformationfromfile!\n");
return-1;//Couldn'tfindstreaminformation
}
/*Dumpinformationaboutfileontostandarderror*/
dump_format(pFormatCtx,0,argv[1],0);
/*Findthefirstvideoandaudiostream*/
videoStream=-1;
audioStream=-1;
subtitleStream=-1;
for(i=0;i<pFormatCtx->nb_streams;i++){
if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO&&videoStream<0)
videoStream=i;
elseif(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO&&audioStream<0)
audioStream=i;
else(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_SUBTITLE&&subtitleStream<0)
subtitleStream=i;
}
if(videoStream==-1){
printf("Couldn'tfineavideostream!\n");
return-1;
}
if(audioStream==-1){
printf("Couldn'tfindaaudiostream!\n");
return-1;
}
if(subtitleStream==-1){
printf("Couldn'tfindasubtitleStream!\n");
//Don'treturn-1,weplaythisfilewhithoutsubtitle.
}
/*Getapointertothecodeccontextforthevideostream,andopenthsvideocodec.*/
pCodecCtx=pFormatCtx->streams[videoStream]->codec;
if((pCodec=avcodec_find_decoder(pCodecCtx->codec_id))==NULL){
printf("UnsupportedpCodec,pleaseprovideanothervideofile!\n");
return-1;
}
if(avcodec_open(pCodecCtx,pCodec)<0){
printf("Couldn'topenvideocodec!\n");
return-1;
}
/*Getapointertothecodeccontextfortheaudiostream,andopentheaudiocodec.*/
aCodecCtx=pFormatCtx->streams[audioStream]->codec;
if((aCodec=avcodec_find_decoder(aCodecCtx->codec_id))==NULL){
printf("UnsupportedaCodec,pleaseprovideanothervideofile!\n");
return-1;
}
if(avcodec_open(aCodecCtx,aCodec)<0){
printf("Couldn'topenauciocodec!\n");//Don'treturn-1,playthevideofilewhitsilence.
return-1;
}
/*Getapointertothecodeccontextforthesubtitlestream,andopenthesubtitlecodec.*/
sCodecCtx=pFormatCtx->streams[subtitleStream]->codec;
if((sCodec=avcodec_find_decoder(aCodecCtx->codec_id))==NULL){
prinft("UnsuppertedsCodec,wewillnotdecodesubtitlestream!\n");
//Don'treturn-1,weplaythiefilewhithoutsubtitle.
}
if(avcodec_open(sCodecCtx,sCodec)<0){
printf("Couldn'topensubtitlecodec!\n");
}
/*Enterintodecodefunction,itcreatedecodethread*/
avit_decode(pFormatCtx,aCodecCtx,pCodecCtx,sCodecCtx,subtitleStream);
/*ReadframeintopacketandputthepacketintoPacketQueues*/
while(av_read_frame(pFormatCtx,&packet)>=0){
switch(packet.stream_index){
casevideoStream:
packet_queue_put(&videoq,&packet);
break;
caseaudioStream:
packet_queue_put(&audioq,&packet);
break;
casesubtitleStream:
packet_queue_put(&subtitleq,&packet);
break;
default:
av_free_packet(&packet);
break;
}
}
/*WhenreadpackettotheQueuePacketFinish,waitfordecodefinish.*/
/*Waitforthreadfinished*/
/*------------------------*/
sleep(60);
quit=1;
//Closethecodec
avcodec_close(pCodecCtx);
avcodec_close(aCodecCtx);
avcodec_close(sCodecCtx);
av_close_input_file(pFormatCtx);
return0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息