我是靠谱客的博主 虚心树叶,最近开发中收集的这篇文章主要介绍FFMPEG解复用、解码测试,音频保存WAV文件,视频保存为PPM图像1. WAV(PCM)文件格式分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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

WAVE文件作为多媒体中使用的声波文件格式之一,它是以RIFF格式为标准的。
RIFF是英文Resource Interchange File Format的缩写,每个WAVE文件的头四个字节便是“RIFF”。
WAVE文件由文件头和数据体两大部分组成。其中文件头又分为RIFF/WAV文件标识段和声音数据格式说明段两部分。
WAVE文件各部分内容及格式见附表。
  常见的声音文件主要有两种,分别对应于单声道(11.025KHz采样率、8Bit的采样值)和双声道(44.1KHz采样率、16Bit的采样值)。
采样率是指:声音信号在“模→数”转换过程中单位时间内采样的次数。采样值是指每一次采样周期内声音模拟信号的积分值。
  对于单声道声音文件,采样数据为八位的短整数(short int 00H-FFH);而对于双声道立体声声音文件,每次采样数据为一个16位的整数(int),高八位和低八位分别代表左右两个声道。
      WAVE文件数据块包含以脉冲编码调制(PCM)格式表示的样本。WAVE文件是由样本组织而成的。
      在单声道WAVE文件中,声道0代表左声道,声道1代表右声道。在多声道WAVE文件中,样本是交替出现的。
  WAVE文件格式说明表  
  偏移地址     字节数    数据类型           内 容
 
  文件头
  00H                4            char             "RIFF"标志
  04H                4          long int           文件长度
  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          long int            波形音频数据传送速率,其值为通道数×每秒数据位数×每   样本的数据位数/8。播放软件利用此值可以估计缓冲区的大小。
  20H              2               int               数据块的调整数(按字节算的),其值为通道数×每样本的数据位值/8。播放软件需要一次处理多个该值大小的字节数据,以便将其值用于缓冲区的调整。
  22H              2                               每样本的数据位数,表示每个声道中各个样本的数据位数。如果有多个声道,对每个声道而言,样本大小都一样。
  24H              4           char                数据标记符"data"
  28H              4         long int             语音数据的长度
  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          unsigned int           225          0

  16位PCM        int                         32767     -32767


2.  FFMPEG解复用、解码测试,保存WAV音频文件和PPM图像文件,字幕的处理与保存未做完。

代码如下:

/*************************************************************************************
** Notice:
Copyright (c) 2011 AVIT Corporation - All Rights Reserved
**
** Name:
example.c
**
** Author:
Tang Qi
**
** Date:
2011-08-02
**
** Version:
1.0
**
** Description: The example is use ffmepg to Demux Video Files.We can prove the result
**
of demux is right.
**
** History:
2011-08-02 Tang Qi Created
**
*************************************************************************************/


#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <stdio.h>
#include <pthread.h>
/* May be follow header file don't need */
#include <stdlib.h>
#include <time.h>

#define MAX_SAVE_FRAME 40
#define MAX_AUDIO_BUF 20000000

/* 定义全局变量 */ 
pthread_mutex_t mutex;
pthread_cond_t cond;
int quit = 0;

/* Define DWORD and WORD */
typedef unsigned long DWORD;
/* 4 Bytes */
typedef unsigned short WORD;
/* 2 Bytes */

/* The struct of wave header */
/* ------------------------- */
typedef struct RIFF_HEADER{
char
avit_szRiffID[4];
/* char = "RIFF" */
DWORD
avit_dwRiffSize;
/* filesize - 8 */
char
avit_szRiffFormat[4]; /*char = "WAVE" */
}RIFF_HEADER;

typedef struct WAVE_FORMAT{
char
avit_szWaveID[4];
/* char = "fmt" */ 
DWORD avit_dwFSize;/* 过渡字节 Ox10 */
WORD
avit_wFormaTag;
/* 编码格式,包括WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM等 */
WORD
avit_wChannels;
/* 声道数,单声道为1,双声道为2 */
DWORD avit_dwSamplesPerSec;
/* 采样频率 */
DWORD avit_dwAvgBytesPerSec; /* 每秒的数据量 */
WORD
avit_wBlockAlign;
/* 块对齐 */
WORD
avit_wBitsPerSample;
/* WAVE文件的采样大小 */
//WORD
sbSize;
/* PCM中忽略此值 */
}WAVE_FORMAT;

typedef struct DATA_BLOCK{
char avit_szDataID[4];
/* char = "data" */
DWORD avit_dwDataSize;/* datasize = filesize - 44 */
}DATA_BLOCK;

/* The struct of PacketQueue is used to save packet. */
/* ------------------------------------------------- */ 
typedef struct PacketQueue {
AVPacketList *first_pkt, *last_pkt;
int nb_packets;
int size;
} PacketQueue;

/* define audio and video PacketQueue*/
PacketQueue audioq;
PacketQueue videoq;
PacketQueue subtitleq;

/* The handle of packet queue */
/* -------------------------- */
void packet_queue_init(PacketQueue *q) 
{

memset(q, 0, sizeof(PacketQueue));

pthread_mutex_init (&mutex, NULL);//create mutex 

pthread_cond_init (&cond, PTHREAD_PROCESS_PRIVATE);//create cond
}

int packet_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);

return 0;
}

static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
{

AVPacketList *pkt1;

int ret;


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;

} else if (!block) {

ret = 0;

break;

} else {

pthread_cond_signal(&cond);

}

}

pthread_mutex_unlock(&mutex);

return ret;
}

void save_video_frame(AVFrame *pFrame, int width, int height, int iFrame)
{

FILE *frameFile;

char szFilename[32];

int
h;


/* Create file name and open file */

sprintf(szFilename, "frame%d.ppm", iFrame);

frameFile=fopen(szFilename, "wb");

if(frameFile==NULL)

return;


/* Write frameFile header */

fprintf(frameFile, "P6n%d %dn255n", width, height);


/* Write pixel data */

for(h=0; h<height; h++)

fwrite(pFrame->data[0]+h*pFrame->linesize[0], 1, width*3, frameFile);


/* Close the frameFile */

fclose(frameFile);
return;
}

void video_thread(AVCodecContext *pCodecCtx)
{ 

AVPacket pkt1, *packet = &pkt1;

int len1, frameFlag, numBytes, i;

AVFrame *pFrame, *pFrameRGB;

uint8_t *buffer;


printf("EC: video_thread Inn");

i = 0;

pFrame = avcodec_alloc_frame();


/* Alloc buffer to pFrameRGB */

if((pFrameRGB = avcodec_alloc_frame()) == NULL)

return;

/* Determine required buffer size and allocate buffer */

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; //quit getting packets

}

/* Decode video frame */

len1 = avcodec_decode_video2(pCodecCtx, pFrame, &frameFlag, packet);


/* Did we get a video frame? */

if(frameFlag) {

/* Convert the image from its native format to RGB */

struct SwsContext *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);


/* Save the frame to disk */

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 ;
}

void write_wave_header(AVCodecContext *aCodecCtx, FILE *pFile, int filesize)
{

/* Add Header into the file which is fill up pcm data,and make this file can play */

/* Write header from the beginning of file */

fseek(pFile, 0, SEEK_SET);

RIFF_HEADER riffHeader;

memcpy(riffHeader.avit_szRiffID, "RIFF", 4);// 1-4 byte

riffHeader.avit_dwRiffSize = filesize - 8;

memcpy(riffHeader.avit_szRiffFormat, "WAVE", 4);

fwrite(&riffHeader, 1, sizeof(riffHeader), pFile);


/* Write waveformat */

WAVE_FORMAT waveFormat;

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 = %dn",

waveFormat.avit_wChannels,waveFormat.avit_dwSamplesPerSec,waveFormat.avit_wBlockAlign, 

waveFormat.avit_dwAvgBytesPerSec,waveFormat.avit_wBitsPerSample );


/* Data Block */

DATA_BLOCK datablock;

memcpy(datablock.avit_szDataID, "data", 4); 

datablock.avit_dwDataSize = filesize - 44; // 41-44 byte,calculated

fwrite(&datablock, 1, sizeof(datablock), pFile);

printf("EC:audio_thread(), THe len of the PCM File is %d,End of the audio_decoden", filesize);


fclose(pFile);

return;
}

/* Read packet from PakcetQueue,and decode audio data */
int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf, int buf_size) 
{

static AVPacket pkt,pkt_temp;

static uint8_t *audio_pkt_data = NULL;

static int audio_pkt_size = 0;


int len1, 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() too old, change to avcodec_decode_audio3() */

if(len1 < 0) {

/* if error, skip this frame */

pkt_temp.size = 0;

break;

}


pkt_temp.data += len1;

pkt_temp.size
-= len1;


if(data_size <= 0) {

/* No data yet, get more frames */
	continue;

}

/* We have data, return it and come back for more later */

return data_size;

}


/* free the current packet */

if(pkt.data)

av_free_packet(&pkt);


/* 

if(quit) {

return -1;

}*/


/* read next packet from audio PacketQueue */

if(packet_queue_get(&audioq, &pkt, 1) < 0) {

return -1;

}

pkt_temp.data = pkt.data;

pkt_temp.size
= pkt.size;
}
}

void audio_thread(AVCodecContext *aCodecCtx)
{

int len1, audio_size, len, ture,filesize,n;


static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];

static unsigned int audio_buf_size = 0;

static unsigned int audio_buf_index = 0;


len = MAX_AUDIO_BUF;

n = 1;

/* Creat and open a File */

FILE *pFile;

char filename[32];

sprintf(filename, "test%d.wav", n);

pFile = fopen(filename, "wb");


/* AT 44 bytes pointer, write data to pFile */

fseek(pFile, 44, SEEK_SET);

filesize = 44;

//ture = 1;
 

/* decode audio frame */

while(len > 0) {

if(audio_buf_index >= audio_buf_size) {

/* We have already sent all our data; get more */ 

audio_size = audio_decode_frame(aCodecCtx, audio_buf, sizeof(audio_buf));


/* Save audio_buf to the PCM File. */

if(audio_size> 0){


fwrite(audio_buf, 1, audio_size, pFile);


filesize += audio_size;


printf("EC: audio_thread() THe len of the PCM File is %dn", filesize);

}


if(audio_size < 0) {

/* If error, output silence */ 

audio_buf_size = 1024; // arbitrary?

memset(audio_buf, 0, audio_buf_size);

printf("EC: audio_thread() *****Output silence *****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 = %dn",
	audio_size, audio_buf_size, audio_buf_index, len, len1);


// memcpy(stream, (uint8_t *)audio_buf + audio_buf_index, len1);

//stream += len1;


len -= len1;

audio_buf_index += len1;

}


/* write wave header to this file*/

write_wave_header(aCodecCtx, pFile, filesize);

return;
}

void subtitle_thread(AVCodecContext *sCodecCtx)
{ 

SubPicture *sp;

AVPacket pkt1, *pkt = &pkt1;

int len1, got_subtitle;

int i;

FILE *textFile;
char filename[32];
int text_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 = %dn", sp->sub.format, len1);
for(i = 0; i < sp->sub.num_rects; i++){
switch(sp->sub.rects[i]->type){
case SUBTITLE_TEXT:
printf("EC: subtitle() Enter in save SUBTITLE_TEXTn");
fwrite(sp->sub.rects[i]->text, 1, sizeof(sp->sub.rects[i]->text), textFile);
break;

case SUBTITLE_ASS:
printf("EC: subtitle() Enter in save SUBTITLE_ASSn");
break;

case SUBTITLE_BITMAP:
printf("EC: subtitle() Enter in save SUBTITLE_BITMAPn");
break;

default:
printf("EC: subtitle() Enter in save SUBTITLE_NONEn");
break;
}

}

}

av_free_packet(pkt);

}
return;
}

void avit_decode(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx, 
AVCodecContext *aCodecCtx, AVCodecContext * sCodecCtx,int subtitle_flag)
{
pthread_t audio_id; 
pthread_t video_id;
pthread_t subtitle_id;

/* Create video decode thread */
if(pthread_create(&video_id, NULL, (void *)video_thread, pCodecCtx) != 0)
printf("Create video thread failure!n");
 
/* Create audio decode thread */
if(pthread_create(&audio_id, NULL, (void *)audio_thread, aCodecCtx) != 0)
printf("Create audio thread failure!n");

/* Create subtitle decode thread */
if(subtitle_flag != -1){
if(pthread_create(&subtitle_id, NULL, (void *)subtitle_thread, sCodecCtx) != 0 )
printf("Create subtitle thread failure!n");
}

return;
}

int main(int argc, char *argv[]) 
{

int i, videoStream, audioStream, subtitleStream, frameFinished;

AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx, *aCodecCtx, *sCodecCtx; 

AVCodec
*pCodec, *aCodec, *sCodec;
AVPacket
packet;


if(argc < 2) {

fprintf(stderr, "Usage: test <file>n");

exit(1);

}


/* Register all formats and codecs */

av_register_all();

/* Init audio PacketQueue and video PacketQueue.*/
packet_queue_init(&audioq);

packet_queue_init(&videoq);
packet_queue_init(&subtitleq)


/* Open video file */

if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0){
printf("Couldn't open this file,Please provide another one!n");

return -1; // Couldn't open this file

}


/* Find stream information */

if(av_find_stream_info(pFormatCtx)<0){
printf("Couldn't find stream information from file!n");

return -1; // Couldn't find stream information

}


/* Dump information about file onto standard error */

dump_format(pFormatCtx, 0, argv[1], 0);


/* Find the first video and audio stream */

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;

else if(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't fine a video stream!n");
return -1;
}

if(audioStream == -1){
printf("Couldn't find a audio stream!n");
return -1;
}

if(subtitleStream == -1){
printf("Couldn't find a subtitle Stream!n");
//Don't return -1,we play this file whithout subtitle.
}


/* Get a pointer to the codec context for the video stream, and open ths video codec. */

pCodecCtx=pFormatCtx->streams[videoStream]->codec;

if((pCodec = avcodec_find_decoder(pCodecCtx->codec_id)) == NULL){
printf("Unsupported pCodec, please provide another video file!n");
return -1;
}

if(avcodec_open(pCodecCtx, pCodec) < 0){
printf("Couldn't open video codec!n");

return -1;
} 

/* Get a pointer to the codec context for the audio stream, and open the audio codec. */
aCodecCtx=pFormatCtx->streams[audioStream]->codec;

if((aCodec = avcodec_find_decoder(aCodecCtx->codec_id)) == NULL){

printf("Unsupported aCodec, please provide another video file!n");

return -1;

}

if(avcodec_open(aCodecCtx, aCodec) <0 ){
printf("Couldn't open aucio codec!n");// Don't return -1, play the video file whit silence.
return -1;
}

/* Get a pointer to the codec context for the subtitle stream, and open the subtitle codec. */
sCodecCtx = pFormatCtx->streams[subtitleStream]->codec;
if((sCodec = avcodec_find_decoder(aCodecCtx->codec_id)) == NULL){
prinft("Unsupperted sCodec, we will not decode subtitle stream!n");
//Don't return -1, we play thie file whithout subtitle.
}
if(avcodec_open(sCodecCtx, sCodec) < 0){
printf("Couldn't open subtitle codec!n");
}

/* Enter into decode function,it create decode thread */
avit_decode(pFormatCtx, aCodecCtx, pCodecCtx,sCodecCtx, subtitleStream);


/* Read frame into packet and put the packet into PacketQueues */

while(av_read_frame(pFormatCtx, &packet)>=0) {
switch(packet.stream_index){
case videoStream:
packet_queue_put(&videoq, &packet);
break;
case audioStream:
packet_queue_put(&audioq, &packet);
break;
case subtitleStream:
packet_queue_put(&subtitleq, &packet);
break;
default:
av_free_packet(&packet);
break;
} 

}

/* When read
packet to the QueuePacket Finish, wait for decode finish.*/

/* Wait for thread finished */
/* ------------------------ */

sleep(60);
quit = 1;

// Close the codec

avcodec_close(pCodecCtx);

avcodec_close(aCodecCtx);
avcodec_close(sCodecCtx);

av_close_input_file(pFormatCtx);


return 0;
}



最后

以上就是虚心树叶为你收集整理的FFMPEG解复用、解码测试,音频保存WAV文件,视频保存为PPM图像1. WAV(PCM)文件格式分析的全部内容,希望文章能够帮你解决FFMPEG解复用、解码测试,音频保存WAV文件,视频保存为PPM图像1. WAV(PCM)文件格式分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部