我们知道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 的情况下就返回结果了
剩下的代码就不用写了,和平常的编解码一样了,