SmartAudio/package/allwinner/tina_multimedia/libcedarx/demo/recoderdemo/recoderdemo.c

761 lines
20 KiB
C
Executable File

/*
* Copyright (c) 2008-2016 Allwinner Technology Co. Ltd.
* All rights reserved.
*
* File : recoderdemo.c
* Description : recoderdemo
* History :
*
*/
#define LOG_TAG "recoderdemo"
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#include <errno.h>
#include <cdx_config.h>
#include <cdx_log.h>
#include <CdxQueue.h>
#include <AwPool.h>
#include <CdxBinary.h>
#include <CdxMuxer.h>
#include <CdxIon.h>
#include "memoryAdapter.h"
#include "awencoder.h"
#include "RecoderWriter.h"
#define SAVE_VIDEO_FRAME (0)
#define AUDIO_INPUT (1)
#define VIDEO_INPUT (1)
static const int STATUS_IDEL = 0;
FILE* inputPCM = NULL;
FILE* inputYUV = NULL;
char pcm_path[128] = {0};
char yuv_path[128] = {0};
int videoEos = 0;
int audioEos = 0;
typedef struct DemoRecoderContext
{
AwEncoder* mAwEncoder;
int callbackData;
pthread_mutex_t mMutex;
VideoEncodeConfig videoConfig;
AudioEncodeConfig audioConfig;
CdxMuxerT* pMuxer;
int muxType;
char pUrl[1024];
CdxWriterT* pStream;
char* pOutUrl;
unsigned char* extractDataBuff;
unsigned int extractDataLength;
pthread_t muxerThreadId ;
pthread_t audioDataThreadId ;
pthread_t videoDataThreadId ;
AwPoolT *pool;
CdxQueueT *dataQueue;
int exitFlag ;
unsigned char* pAddrPhyY;
unsigned char* pAddrPhyC;
int bUsed;
FILE* fpSaveVideoFrame;
}DemoRecoderContext;
//* a notify callback for AwEncorder.
void NotifyCallbackForAwEncorder(void* pUserData, int msg, void* param)
{
DemoRecoderContext* pDemoRecoder = (DemoRecoderContext*)pUserData;
switch(msg)
{
case AWENCODER_VIDEO_ENCODER_NOTIFY_RETURN_BUFFER:
{
int id = *((int*)param);
if(id == 0)
{
pDemoRecoder->bUsed = 0;
}
break;
}
default:
{
printf("warning: unknown callback from AwRecorder.\n");
break;
}
}
return ;
}
int onVideoDataEnc(void *app,CdxMuxerPacketT *buff)
{
CdxMuxerPacketT *packet = NULL;
DemoRecoderContext* pDemoRecoder = (DemoRecoderContext*)app;
if (!buff)
return 0;
packet = (CdxMuxerPacketT*)malloc(sizeof(CdxMuxerPacketT));
packet->buflen = buff->buflen;
packet->length = buff->length;
packet->buf = malloc(buff->buflen);
memcpy(packet->buf, buff->buf, packet->buflen);
packet->pts = buff->pts;
packet->type = buff->type;
packet->streamIndex = buff->streamIndex;
packet->duration = buff->duration;
#if SAVE_VIDEO_FRAME
if(pDemoRecoder->fpSaveVideoFrame)
{
fwrite(packet->buf, 1, packet->buflen, pDemoRecoder->fpSaveVideoFrame);
}
#endif
CdxQueuePush(pDemoRecoder->dataQueue,packet);
return 0;
}
int onAudioDataEnc(void *app,CdxMuxerPacketT *buff)
{
CdxMuxerPacketT *packet = NULL;
DemoRecoderContext* pDemoRecoder = (DemoRecoderContext*)app;
if (!buff)
return 0;
packet = (CdxMuxerPacketT*)malloc(sizeof(CdxMuxerPacketT));
packet->buflen = buff->buflen;
packet->length = buff->length;
packet->buf = malloc(buff->buflen);
memcpy(packet->buf, buff->buf, packet->buflen);
packet->pts = buff->pts;
packet->type = buff->type;
packet->streamIndex = buff->streamIndex;
CdxQueuePush(pDemoRecoder->dataQueue,packet);
return 0;
}
void* MuxerThread(void *param)
{
//int ret = 0;
int i =0;
CdxMuxerPacketT *mPacket = NULL;
DemoRecoderContext *p = (DemoRecoderContext*)param;
RecoderWriterT *rw = NULL;
#if FS_WRITER
CdxFsCacheMemInfo fs_cache_mem;
int fs_mode = FSWRITEMODE_DIRECT;
// int fs_cache_size = 1024 * 1024;
#endif
logd("MuxerThread");
if(p->pUrl)
{
if ((p->pStream = CdxWriterCreat(p->pUrl)) == NULL)
{
loge("CdxWriterCreat() failed");
return 0;
}
rw = (RecoderWriterT*)p->pStream;
rw->file_mode = FD_FILE_MODE;
strcpy(rw->file_path, p->pUrl);
RWOpen(p->pStream);
p->pMuxer = CdxMuxerCreate(p->muxType, p->pStream);
if(p->pMuxer == NULL)
{
loge("CdxMuxerCreate failed");
return 0;
}
logd("MuxerThread init ok");
}
CdxMuxerMediaInfoT mediainfo;
memset(&mediainfo, 0, sizeof(CdxMuxerMediaInfoT));
switch (p->audioConfig.nType)
{
case AUDIO_ENCODE_PCM_TYPE:
mediainfo.audio.eCodecFormat = AUDIO_ENCODER_PCM_TYPE;
break;
case AUDIO_ENCODE_AAC_TYPE:
mediainfo.audio.eCodecFormat = AUDIO_ENCODER_AAC_TYPE;
break;
case AUDIO_ENCODE_MP3_TYPE:
mediainfo.audio.eCodecFormat = AUDIO_ENCODER_MP3_TYPE;
break;
case AUDIO_ENCODE_LPCM_TYPE:
mediainfo.audio.eCodecFormat = AUDIO_ENCODER_LPCM_TYPE;
break;
default:
loge("unlown audio type(%d)", p->audioConfig.nType);
break;
}
#if AUDIO_INPUT
mediainfo.audioNum = 1;
#endif
#if VIDEO_INPUT
mediainfo.videoNum = 1;
#endif
if(p->muxType == CDX_MUXER_AAC)
{
mediainfo.videoNum = 0;
}
mediainfo.audio.nAvgBitrate = p->audioConfig.nBitrate;
mediainfo.audio.nBitsPerSample = p->audioConfig.nSamplerBits;
mediainfo.audio.nChannelNum = p->audioConfig.nOutChan;
mediainfo.audio.nMaxBitRate = p->audioConfig.nBitrate;
mediainfo.audio.nSampleRate = p->audioConfig.nOutSamplerate;
mediainfo.audio.nSampleCntPerFrame = 1024; // aac
if(p->videoConfig.nType == VIDEO_ENCODE_H264)
mediainfo.video.eCodeType = VENC_CODEC_H264;
else if(p->videoConfig.nType == VIDEO_ENCODE_JPEG)
mediainfo.video.eCodeType = VENC_CODEC_JPEG;
else
{
loge("cannot suppot this video type");
return 0;
}
mediainfo.video.nWidth = p->videoConfig.nOutWidth;
mediainfo.video.nHeight = p->videoConfig.nOutHeight;
mediainfo.video.nFrameRate = p->videoConfig.nFrameRate;
logd("******************* mux mediainfo *****************************");
logd("videoNum : %d", mediainfo.videoNum);
logd("audioNum : %d", mediainfo.audioNum);
logd("videoTYpe : %d", mediainfo.video.eCodeType);
logd("framerate : %d", mediainfo.video.nFrameRate);
logd("width : %d", mediainfo.video.nWidth);
logd("height : %d", mediainfo.video.nHeight);
logd("**************************************************************");
if(p->pMuxer)
{
CdxMuxerSetMediaInfo(p->pMuxer, &mediainfo);
#if FS_WRITER
memset(&fs_cache_mem, 0, sizeof(CdxFsCacheMemInfo));
fs_cache_mem.m_cache_size = 512 * 1024;
fs_cache_mem.mp_cache = (cdx_uint8*)malloc(fs_cache_mem.m_cache_size);
if (fs_cache_mem.mp_cache == NULL)
{
loge("fs_cache_mem.mp_cache malloc failed\n");
return NULL;
}
CdxMuxerControl(p->pMuxer, SET_CACHE_MEM, &fs_cache_mem);
fs_mode = FSWRITEMODE_CACHETHREAD;
/*
fs_cache_size = 1024 * 1024;
CdxMuxerControl(p->pMuxer, SET_FS_SIMPLE_CACHE_SIZE, &fs_cache_size);
fs_mode = FSWRITEMODE_SIMPLECACHE;
*/
//fs_mode = FSWRITEMODE_DIRECT;
CdxMuxerControl(p->pMuxer, SET_FS_WRITE_MODE, &fs_mode);
#endif
}
logd("extractDataLength %d",p->extractDataLength);
if(p->extractDataLength > 0 && p->pMuxer)
{
logd("demo WriteExtraData");
if(p->pMuxer)
CdxMuxerWriteExtraData(p->pMuxer, p->extractDataBuff, p->extractDataLength, 0);
}
if(p->pMuxer)
{
logd("write head");
CdxMuxerWriteHeader(p->pMuxer);
}
#if AUDIO_INPUT && VIDEO_INPUT
while ((audioEos==0) || (videoEos==0))
#elif VIDEO_INPUT
while(videoEos==0)
#elif AUDIO_INPUT
while(audioEos==0)
#endif
{
while (!CdxQueueEmpty(p->dataQueue))
{
mPacket = CdxQueuePop(p->dataQueue);
i++;
if(p->pMuxer)
{
if(CdxMuxerWritePacket(p->pMuxer, mPacket) < 0)
{
loge("+++++++ CdxMuxerWritePacket failed");
}
}
free(mPacket->buf);
free(mPacket);
}
usleep(1*1000);
}
if(p->pMuxer)
{
logd("write trailer");
CdxMuxerWriteTrailer(p->pMuxer);
}
logd("CdxMuxerClose");
if(p->pMuxer)
{
CdxMuxerClose(p->pMuxer);
p->pMuxer = NULL;
}
if(p->pStream)
{
RWClose(p->pStream);
CdxWriterDestroy(p->pStream);
p->pStream = NULL;
rw = NULL;
}
#if FS_WRITER
if(fs_cache_mem.mp_cache)
{
free(fs_cache_mem.mp_cache);
fs_cache_mem.mp_cache = NULL;
}
#endif
logd("MuxerThread has finish!");
p->exitFlag = 1;
return 0;
}
void* AudioInputThread(void *param)
{
int ret = 0;
//int i =0;
DemoRecoderContext *p = (DemoRecoderContext*)param;
logd("AudioInputThread");
int num = 0;
int size2 = 0;
int64_t audioPts = 0;
AudioInputBuffer audioInputBuffer;
memset(&audioInputBuffer, 0x00, sizeof(AudioInputBuffer));
audioInputBuffer.nLen = 1024*4; //176400;
audioInputBuffer.pData = (char*)malloc(audioInputBuffer.nLen);
while(num<1024)
{
ret = -1;
if(!audioEos)
{
if (inputPCM == NULL)
{
printf("before fread, inputPCM is NULL\n");
break;
}
size2 = fread(audioInputBuffer.pData, 1, audioInputBuffer.nLen, inputPCM);
if(size2 < audioInputBuffer.nLen)
{
logd("read error");
audioEos = 1;
}
while(ret)
{
audioInputBuffer.nPts = audioPts;
ret = AwEncoderWritePCMdata(p->mAwEncoder,&audioInputBuffer);
//logd("=== WritePCMdata audioPts : %lld", audioPts);
usleep(10*1000);
}
usleep(20*1000);
audioPts += 23;
}
num ++;
}
logd("audio read data finish!");
audioEos = 1;
return 0;
}
void* VideoInputThread(void *param)
{
DemoRecoderContext *p = (DemoRecoderContext*)param;
logd("VideoInputThread");
VideoInputBuffer videoInputBuffer;
int sizeY = p->videoConfig.nSrcHeight* p->videoConfig.nSrcWidth;
if(p->videoConfig.bUsePhyBuf)
{
CdxIonOpen();
p->pAddrPhyY = CdxIonPalloc(sizeY);
p->pAddrPhyC = CdxIonPalloc(sizeY/2);
printf("==== palloc demoRecoder.pAddrPhyY: %p\n", p->pAddrPhyY);
videoInputBuffer.nID = 0;
fread(p->pAddrPhyY, 1, sizeY, inputYUV);
fread(p->pAddrPhyC, 1, sizeY/2, inputYUV);
CdxIonFlushCache(p->pAddrPhyY, sizeY);
CdxIonFlushCache(p->pAddrPhyC, sizeY/2);
videoInputBuffer.nID = 0;
videoInputBuffer.pAddrPhyY = CdxIonPhy2Vir(p->pAddrPhyY);
videoInputBuffer.pAddrPhyC = CdxIonPhy2Vir(p->pAddrPhyC);
}
else
{
memset(&videoInputBuffer, 0x00, sizeof(VideoInputBuffer));
videoInputBuffer.nLen = p->videoConfig.nSrcHeight* p->videoConfig.nSrcWidth *3/2;
videoInputBuffer.pData = (unsigned char*)malloc(videoInputBuffer.nLen);
}
unsigned int size1;
long long videoPts = 0;
int ret = -1;
int num = 0;
while(num<100)
{
ret = -1;
if(p->videoConfig.bUsePhyBuf)
{
while(1)
{
if(p->bUsed == 0)
{
break;
}
//printf("==== wait buf return, demoRecoder.bUsed: %d \n", demoRecoder.bUsed);
usleep(10000);
}
videoInputBuffer.nID = 0;
fread(p->pAddrPhyY, 1, sizeY, inputYUV);
fread(p->pAddrPhyC, 1, sizeY/2, inputYUV);
CdxIonFlushCache(p->pAddrPhyY, sizeY);
CdxIonFlushCache(p->pAddrPhyC, sizeY/2);
videoInputBuffer.nID = 0;
videoInputBuffer.pAddrPhyY = CdxIonVir2Phy(p->pAddrPhyY);
videoInputBuffer.pAddrPhyC = CdxIonVir2Phy(p->pAddrPhyC);
}
else
{
size1 = fread(videoInputBuffer.pData, 1, videoInputBuffer.nLen, inputYUV);
if(size1 < videoInputBuffer.nLen)
{
logd("read error");
videoEos = 1;
}
}
while(ret < 0)
{
videoInputBuffer.nPts = videoPts;
p->bUsed = 1;
//printf("==== writeYUV used: %d", demoRecoder.bUsed);
ret = AwEncoderWriteYUVdata(p->mAwEncoder,&videoInputBuffer);
usleep(10*1000);
}
usleep(29*1000);
videoPts += 30;
num ++;
}
logd("video read data finish!");
videoEos = 1;
printf("==== freee demoRecoder.pAddrPhyY: %p\n", p->pAddrPhyY);
if(p->pAddrPhyY)
{
CdxIonPfree(p->pAddrPhyY);
}
printf("==== freee demoRecoder.pAddrPhyY end\n");
if(p->pAddrPhyC)
{
CdxIonPfree(p->pAddrPhyC);
}
CdxIonClose();
if (inputYUV)
{
fclose(inputYUV);
inputYUV = NULL;
}
return 0;
}
//* the main method.
int main(int argc, char *argv[])
{
DemoRecoderContext demoRecoder;
EncDataCallBackOps mEncDataCallBackOps;
CdxMuxerPacketT *mPacket = NULL;
mEncDataCallBackOps.onAudioDataEnc = onAudioDataEnc;
mEncDataCallBackOps.onVideoDataEnc = onVideoDataEnc;
printf("\n");
printf("************************************************************************\n");
printf("* This program implements a simple recoder.\n");
printf("* Inplemented by Allwinner ALD-AL3 department.\n");
printf("***********************************************************************\n");
if(argc < 3)
{
printf("run failed \n");
printf("./recoderdemo argv[1] argv[2] \n");
printf(" argv[1]: video yuv data file \n");
printf(" argv[2]: audio pcm file \n");
return -1;
}
#if VIDEO_INPUT
inputYUV = fopen(argv[1], "rb");
logd("fopen inputYUV == %p\n", inputYUV);
if(inputYUV == NULL)
{
printf("open yuv file failed");
return -1;
}
#endif
#if AUDIO_INPUT
inputPCM = fopen(argv[2], "rb");
logd("fopen inputPCM == %p\n", inputPCM);
if(inputPCM == NULL)
{
printf("open pcm file failed");
return -1;
}
#endif
//* create a demoRecoder.
memset(&demoRecoder, 0, sizeof(DemoRecoderContext));
demoRecoder.pool = AwPoolCreate(NULL);
demoRecoder.dataQueue = CdxQueueCreate(demoRecoder.pool);
#if SAVE_VIDEO_FRAME
demoRecoder.fpSaveVideoFrame = fopen("/mnt/UDISK/video.dat", "wb");
if(demoRecoder.fpSaveVideoFrame == NULL)
{
printf("open file /mnt/UDISK/video.dat failed, errno(%d)\n", errno);
}
#endif
//VideoEncodeConfig videoConfig;
memset(&demoRecoder.videoConfig, 0x00, sizeof(VideoEncodeConfig));
demoRecoder.videoConfig.nType = VIDEO_ENCODE_JPEG;
demoRecoder.videoConfig.nFrameRate = 30;
demoRecoder.videoConfig.nOutHeight = 720;
demoRecoder.videoConfig.nOutWidth = 1280;
demoRecoder.videoConfig.nSrcHeight = 720;
demoRecoder.videoConfig.nSrcWidth = 1280;
demoRecoder.videoConfig.nBitRate = 3*1000*1000;
demoRecoder.videoConfig.bUsePhyBuf = 1;
//AudioEncodeConfig audioConfig;
demoRecoder.audioConfig.nType = AUDIO_ENCODE_PCM_TYPE;
demoRecoder.audioConfig.nInChan = 2;
demoRecoder.audioConfig.nInSamplerate = 44100;
demoRecoder.audioConfig.nOutChan = 2;
demoRecoder.audioConfig.nOutSamplerate = 44100;
demoRecoder.audioConfig.nSamplerBits = 16;
demoRecoder.muxType = CDX_MUXER_MOV;
if(demoRecoder.muxType == CDX_MUXER_TS &&
demoRecoder.audioConfig.nType == AUDIO_ENCODE_PCM_TYPE)
{
demoRecoder.audioConfig.nFrameStyle = 2;
}
if(demoRecoder.muxType == CDX_MUXER_TS &&
demoRecoder.audioConfig.nType == AUDIO_ENCODE_AAC_TYPE)
{
demoRecoder.audioConfig.nFrameStyle = 1;
}
if(demoRecoder.muxType == CDX_MUXER_MOV &&
demoRecoder.audioConfig.nType == AUDIO_ENCODE_AAC_TYPE)
{
demoRecoder.audioConfig.nFrameStyle = 1;
}
if(demoRecoder.muxType == CDX_MUXER_AAC)
{
demoRecoder.audioConfig.nType = AUDIO_ENCODE_AAC_TYPE;
demoRecoder.audioConfig.nFrameStyle = 0;
}
if(demoRecoder.muxType == CDX_MUXER_MP3)
{
demoRecoder.audioConfig.nType = AUDIO_ENCODE_MP3_TYPE;
}
pthread_mutex_init(&demoRecoder.mMutex, NULL);
demoRecoder.mAwEncoder = AwEncoderCreate(&demoRecoder);
if(demoRecoder.mAwEncoder == NULL)
{
printf("can not create AwRecorder, quit.\n");
exit(-1);
}
//* set callback to recoder.
AwEncoderSetNotifyCallback(demoRecoder.mAwEncoder,NotifyCallbackForAwEncorder,&(demoRecoder));
if(demoRecoder.muxType == CDX_MUXER_AAC || demoRecoder.muxType == CDX_MUXER_MP3)
{
AwEncoderInit(demoRecoder.mAwEncoder, NULL, &demoRecoder.audioConfig,&mEncDataCallBackOps);
videoEos = 1;
}
else
{
AwEncoderInit(demoRecoder.mAwEncoder, &demoRecoder.videoConfig,
&demoRecoder.audioConfig,&mEncDataCallBackOps);
}
//AwEncoderInit(demoRecoder.mAwEncoder, &demoRecoder.videoConfig, NULL,&mEncDataCallBackOps);
switch(demoRecoder.muxType)
{
case CDX_MUXER_AAC:
sprintf(demoRecoder.pUrl, "/mnt/UDISK/save.aac");
break;
case CDX_MUXER_MP3:
sprintf(demoRecoder.pUrl, "/mnt/UDISK/save.mp3");
break;
case CDX_MUXER_TS:
sprintf(demoRecoder.pUrl, "/mnt/UDISK/save.ts");
break;
default:
sprintf(demoRecoder.pUrl, "/mnt/UDISK/save.mp4");
break;
}
AwEncoderStart(demoRecoder.mAwEncoder);
AwEncoderGetExtradata(demoRecoder.mAwEncoder,&demoRecoder.extractDataBuff,
&demoRecoder.extractDataLength);
#if SAVE_VIDEO_FRAME
if(demoRecoder.fpSaveVideoFrame)
{
fwrite(demoRecoder.extractDataBuff, 1, demoRecoder.extractDataLength,
demoRecoder.fpSaveVideoFrame);
}
#endif
#if AUDIO_INPUT
pthread_create(&demoRecoder.audioDataThreadId, NULL, AudioInputThread, &demoRecoder);
#endif
#if VIDEO_INPUT
if((demoRecoder.muxType != CDX_MUXER_AAC) && (demoRecoder.muxType != CDX_MUXER_MP3))
{
pthread_create(&demoRecoder.videoDataThreadId, NULL, VideoInputThread, &demoRecoder);
}
#endif
pthread_create(&demoRecoder.muxerThreadId, NULL, MuxerThread, &demoRecoder);
while (demoRecoder.exitFlag == 0)
{
logd("wait MuxerThread finish!");
usleep(1000*1000);
}
if(demoRecoder.muxerThreadId)
pthread_join(demoRecoder.muxerThreadId, NULL);
#if AUDIO_INPUT
if(demoRecoder.audioDataThreadId)
pthread_join(demoRecoder.audioDataThreadId, NULL);
#endif
#if VIDEO_INPUT
if(demoRecoder.videoDataThreadId)
pthread_join(demoRecoder.videoDataThreadId, NULL);
#endif
printf("destroy AwRecorder.\n");
while (!CdxQueueEmpty(demoRecoder.dataQueue))
{
logd("free a packet");
mPacket = CdxQueuePop(demoRecoder.dataQueue);
free(mPacket->buf);
free(mPacket);
}
CdxQueueDestroy(demoRecoder.dataQueue);
AwPoolDestroy(demoRecoder.pool);
if(demoRecoder.mAwEncoder != NULL)
{
AwEncoderStop(demoRecoder.mAwEncoder);
AwEncoderDestory(demoRecoder.mAwEncoder);
demoRecoder.mAwEncoder = NULL;
}
pthread_mutex_destroy(&demoRecoder.mMutex);
#if SAVE_VIDEO_FRAME
if(demoRecoder.fpSaveVideoFrame)
fclose(demoRecoder.fpSaveVideoFrame);
#endif
#if VIDEO_INPUT
if (inputYUV)
{
fclose(inputYUV);
inputYUV = NULL;
}
#endif
#if AUDIO_INPUT
if (inputPCM)
{
fclose(inputPCM);
inputPCM = NULL;
}
#endif
printf("\n");
printf("**************************************************************\n");
printf("* Quit the program, goodbye!\n");
printf("**************************************************************\n");
printf("\n");
return 0;
}