我們知道FFmpeg能夠處理本地檔案或者網絡檔案
隻要傳入url給avformat_open_input函數就可以了
實際上對于音視訊的進行中,
很少會給一個完整有效的網址
很多時候都是傳遞流資訊過來
比如h264 和aac的裸流,這些流隻需要調用
ffmpeg 的解碼函數即可。
但對于封裝格式來說,如何把資料傳遞給ffmpeg就成了一個很大的問題
我參考雷曉華的記憶體讀取,知道了ffmpeg 提供了某種回調函數
來讓外部傳入流資料,
int size = 188000;
av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();
unsigned char *aviobuffer=(unsigned char *)av_malloc(size);
AVIOContext *avio =avio_alloc_context(aviobuffer, size,0,NULL,read_buffer,NULL,NULL);
pFormatCtx->pb=avio;
int ret = avformat_open_input(&pFormatCtx,NULL,NULL,NULL);
注意這裡面是沒有任何地方傳遞url 的,read_buffer才是ffmpeg讀取音視訊資料的
地方
int read_buffer(void *opaque, uint8_t *buf, int buf_size){
int cpSize = 0;
YYInputQueue *inputQueue = (YYInputQueue *)[(TSDeMuxer *)object getInputQueue];
while (![(TSDeMuxer *)object stop]) {
if (inputQueue->getQueueSize()>0) {
InputStreamData streamData;
inputQueue->getpacket(streamData);
memcpy((uint8_t *)buf,streamData.data, streamData.size);
buf_size = (int )streamData.size;
printf("input read size=[%d] data=%s\n",buf_size,buf);
cpSize = buf_size;
break;
} else {
usleep(40*1000);
continue;
}
}
return cpSize;
}
這是從隊列裡面取出資料,如果資料沒有就繼續等下去,一直等到資料有為止,
- (void)sendInputDataThread {
//int perSize = 32768;
int perSize = 188000;
FILE *fp_open1=NULL;
NSFileManager* manager = [NSFileManager defaultManager];
NSString *filepath = [[NSBundle mainBundle] pathForResource:@"sdcard" ofType:@"ts"];
long long size = [[manager attributesOfItemAtPath:filepath error:nil] fileSize];
int count = (int ) size/perSize;
fp_open1 = fopen([filepath UTF8String], "r");
for (int i=0;i<=count;i++) {
if(!feof(fp_open1)){
if (self.demuxer.stop) {
break;
}
uint8_t *buf=(uint8_t *)malloc(perSize);;
int buf_size = perSize;
if (i== count) {
buf_size = size - perSize*count;
}
int true_size=fread(buf,1,buf_size,fp_open1);
if (true_size >0) {
printf("input write size=[%d] data=%s\n",true_size,buf);
[self.demuxer sendData:(char *)buf andSize:(int)buf_size andTimeStamp:0];
}
usleep(2000*1000);
}
}
fclose(fp_open1);
}
這裡是發送資料的代碼,可以用來模拟從本地讀取檔案,
然後切成一片一片的片段,每次讀取一段後睡眠一段時間(模拟網絡情況)
然後将片段送入隊列
readpacket 函數會在隊列size大于0 的情況下就傳回結果了
剩下的代碼就不用寫了,和平常的編解碼一樣了,