USB中的数据,是通过解码模块之后,将PCM数据存放在FIFO中,再去写再播放出去。具体的数据流向图如下:
因为USB中的音频解码出来的PCM数据格式各不相同,为得到相同格式的PCM数据,故需要PCM重采样,将原始PCM数据,转换为双声道32位48KHz的PCM数据。
具体的程序流程如下图所示:其中蓝色部分为UDP输出的过程,浅绿色为解码过程,棕色为重采样过程。
简单介绍下流程中各函数意义:
av_register_all():注册FFmpeg所有编解码器。
avformat_ network_init():注册FFmpeg所有网络协议。(如果没有,不能udp、rtmp等输出)
avformat_alloc_output_context2():初始化输出码流的AVFormatContext。
avio_open():打开输出文件。
av_new_stream():创建输出码流的AVStream。
avcodec_find_decoder():查找解码器。
avcodec_open2():打开解码器。
avformat_write_header():写文件头(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。
av_read_frame ():将USB的文件,按帧读取。
avcodec_decode_audio4():将包的数据解码成Pframe
swr_convert ():PCM重采样。即将解码后的PCM数据重采样。
av_write_trailer():写文件尾(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <string.h>
#include "libavformat/avformat.h"
#include "libavutil/mathematics.h"
#include "libavutil/audio_fifo.h"
#include "libswscale/swscale.h"
#include "libavfilter/avfilter.h"
#include "libswresample/swresample.h"
#include "AppGlobal.h"
#include "pelog.h"
#include "ram.h"
#include "block.h"
#include "FPGA.h"
#include "playlist.h"
#include "WSInterface.h"
//#include "block.h"
#define SWR_CH_MAX 32
#define MAX_BUFFER_SIZE 0x100000
#define SWR_SAMPLE_RATE 48000
#define DEBUG_DECODER_FIFO
//#define DEBUG_FFMPEG_FIFO
//#define DEBUG_DECODER_PCM
extern U32 g_PlayProgramID;
extern bool g_USBBlocked;
extern bool g_USBEnd;
extern bool g_USBExit;
extern pthread_t g_decoder_thread;
extern pthread_mutex_t g_decoder_pthread_mutex;
extern pthread_cond_t g_decoder_pthread_cond;
extern PCM_OutputMode g_curOutputMode;
extern char g_heartbeat_status[30];
pthread_t g_ram_write_thread;
pthread_mutex_t g_udpout_mutex;
bool ram_thread_end = false;
/*****************************************************************************
Function: UDP_Lock_Init
Description: UDP Lock init
Input: none
Output: none
Return: none
Author: ruibin.zhang
*****************************************************************************/
void UDP_Lock_Init()
{
pthread_mutex_init(&g_udpout_mutex, NULL);
}
/*****************************************************************************
Function: REG_Lock
Description: Lock UDP out
Input: none
Output: none
Return: none
Author: ruibin.zhang
*****************************************************************************/
void UDP_Lock()
{
pthread_mutex_lock(&g_udpout_mutex);
}
/*****************************************************************************
Function: UDP_UnLock
Description: unLock UDP out
Input: none
Output: none
Return: none
Author: ruibin.zhang
*****************************************************************************/
void UDP_UnLock()
{
pthread_mutex_unlock(&g_udpout_mutex);
}
void get_MacAddr(char *Mac, S32 MacLen, char *EthType)
{
if(!Mac || !EthType)
{
return ;
}
S32 s32Macfd = 0;
struct ifreq Macreq;
s32Macfd = socket(AF_INET, SOCK_DGRAM, 0);
if(s32Macfd < 0)
{
close(s32Macfd);
printf("build socket fail\n");
return ;
}
strcpy(Macreq.ifr_name, EthType);
if(ioctl(s32Macfd, SIOCGIFHWADDR, &Macreq) < 0)
{
close(s32Macfd);
printf("ioctl error\n");
return ;
}
close(s32Macfd);
snprintf(Mac, MacLen, "%02x:%02x:%02x:%02x:%02x:%02x",
Macreq.ifr_hwaddr.sa_data[0],Macreq.ifr_hwaddr.sa_data[1],
Macreq.ifr_hwaddr.sa_data[2],Macreq.ifr_hwaddr.sa_data[3],
Macreq.ifr_hwaddr.sa_data[4],Macreq.ifr_hwaddr.sa_data[5]);
}
/****************************************************************************
*
* NAME
* peErrCode swr_config(struct SwrContext *s, AVFormatContext *ic, S32 stream_index)
*
* PURPOSE:
* config swr
*
* USAGE
* ic->stream[stream_index]->codec is source pcm format