Revision 648357d7 chunker_streamer.c
chunker_streamer.c | ||
---|---|---|
21 | 21 |
//#define DEBUG_CHUNKER |
22 | 22 |
//#define DEBUG_TIME |
23 | 23 |
|
24 |
ChunkerMetadata *cmeta = NULL; |
|
24 | 25 |
|
25 |
/* |
|
26 |
int alphasortNew(const struct dirent **a, const struct dirent **b) { |
|
27 |
int idx1 = atoi((*a)->d_name+5); |
|
28 |
int idx2 = atoi((*b)->d_name+5); |
|
29 |
return (idx2<idx1); |
|
30 |
// return (strcmp((*a)->d_name,(*b)->d_name)); |
|
31 |
} |
|
32 |
*/ |
|
33 |
|
|
34 |
ChunkerMetadata *cmeta=NULL; |
|
35 | 26 |
|
36 | 27 |
int chunkFilled(ExternalChunk *echunk, ChunkerMetadata *cmeta) { |
37 | 28 |
// different strategies to implement |
... | ... | |
113 | 104 |
|
114 | 105 |
int main(int argc, char *argv[]) { |
115 | 106 |
int i=0; |
116 |
int videoStream, outbuf_size, out_size, seq_current_chunk = 1, audioStream; //HINT MORE BYTES IN SEQ |
|
117 |
int len1, data_size; |
|
107 |
|
|
108 |
//output variables |
|
109 |
int seq_current_chunk = 1; //chunk numbering starts from 1; HINT do i need more bytes? |
|
110 |
uint8_t *video_outbuf = NULL; |
|
111 |
int video_outbuf_size, video_frame_size; |
|
112 |
uint8_t *audio_outbuf = NULL; |
|
113 |
int audio_outbuf_size, audio_frame_size; |
|
114 |
int audio_data_size; |
|
115 |
|
|
116 |
//numeric identifiers of input streams |
|
117 |
int videoStream = -1; |
|
118 |
int audioStream = -1; |
|
119 |
|
|
120 |
int len1; |
|
118 | 121 |
int frameFinished; |
119 |
int numBytes, outbuf_audio_size, audio_size; |
|
120 |
int sizeFrame = 0; |
|
121 |
int sizeChunk = 0; |
|
122 |
int dir_entries; |
|
122 |
//frame sequential counters |
|
123 |
int contFrameAudio=0, contFrameVideo=0; |
|
124 |
int numBytes; |
|
125 |
|
|
126 |
//command line parameters |
|
123 | 127 |
int audio_bitrate; |
124 | 128 |
int video_bitrate; |
125 |
int contFrameAudio=0, contFrameVideo=0; |
|
126 |
int live_source=0; |
|
129 |
int live_source = 0; |
|
127 | 130 |
|
128 |
uint8_t *buffer,*outbuf,*outbuf_audio;
|
|
129 |
uint8_t *outbuf_audi_audio,*tempdata;
|
|
130 |
//uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
|
|
131 |
uint16_t *audio_buf = NULL;
|
|
131 |
//a raw buffer for decoded uncompressed audio samples
|
|
132 |
int16_t *samples = NULL;
|
|
133 |
//a raw uncompressed video picture
|
|
134 |
AVFrame *pFrame = NULL;
|
|
132 | 135 |
|
133 |
unsigned int audio_buf_size = 0; |
|
134 |
long double newtimestamp; |
|
135 |
|
|
136 | 136 |
AVFormatContext *pFormatCtx; |
137 | 137 |
AVCodecContext *pCodecCtx,*pCodecCtxEnc,*aCodecCtxEnc,*aCodecCtx; |
138 | 138 |
AVCodec *pCodec,*pCodecEnc,*aCodec,*aCodecEnc; |
139 |
AVFrame *pFrame; |
|
140 |
AVFrame *pFrameRGB; |
|
141 | 139 |
AVPacket packet; |
142 |
int64_t last_pkt_dts=0, delta_video=0, delta_audio=0, last_pkt_dts_audio=0, target_pts=0; |
|
143 | 140 |
|
144 |
Frame *frame=NULL;
|
|
145 |
|
|
146 |
ExternalChunk *chunk=NULL;
|
|
147 |
ExternalChunk *chunkaudio=NULL;
|
|
141 |
//Napa-Wine specific Frame and Chunk structures for transport
|
|
142 |
Frame *frame = NULL; |
|
143 |
ExternalChunk *chunk = NULL;
|
|
144 |
ExternalChunk *chunkaudio = NULL;
|
|
148 | 145 |
|
149 |
char buf[1024], outfile[1024], basedelfile[1024], delfile[1024]; |
|
146 |
//char buf[1024], outfile[1024]; |
|
147 |
|
|
148 |
//stuff needed to compute the right timestamps |
|
150 | 149 |
short int FirstTimeAudio=1, FirstTimeVideo=1; |
151 | 150 |
long long newTime; |
152 |
|
|
153 | 151 |
double ptsvideo1=0.0; |
154 | 152 |
double ptsaudio1=0.0; |
155 |
|
|
156 |
// struct dirent **namelist; |
|
157 |
|
|
153 |
int64_t last_pkt_dts=0, delta_video=0, delta_audio=0, last_pkt_dts_audio=0, target_pts=0; |
|
154 |
|
|
155 |
|
|
156 |
//scan the command line |
|
158 | 157 |
if(argc < 4) { |
159 | 158 |
fprintf(stderr, "execute ./chunker_streamer moviefile audiobitrate videobitrate <live source flag (0 or 1)>\n"); |
160 | 159 |
return -1; |
... | ... | |
168 | 167 |
if(live_source) |
169 | 168 |
fprintf(stderr, "INIT: Using LIVE SOURCE TimeStamps\n"); |
170 | 169 |
|
171 |
audio_buf = (uint16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); |
|
172 |
outbuf_audio_size = 10000; |
|
173 |
outbuf_audio = malloc(outbuf_audio_size); |
|
174 |
|
|
175 | 170 |
// Register all formats and codecs |
176 | 171 |
av_register_all(); |
177 | 172 |
|
178 |
// Open video file
|
|
173 |
// Open input file
|
|
179 | 174 |
if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL) != 0) { |
180 | 175 |
fprintf(stdout, "INIT: Couldn't open video file. Exiting.\n"); |
181 | 176 |
exit(-1); |
... | ... | |
190 | 185 |
// Dump information about file onto standard error |
191 | 186 |
dump_format(pFormatCtx, 0, argv[1], 0); |
192 | 187 |
|
193 |
// Find the first video stream |
|
194 |
videoStream=-1; |
|
195 |
audioStream=-1; |
|
196 |
|
|
188 |
// Find the video and audio stream numbers |
|
197 | 189 |
for(i=0; i<pFormatCtx->nb_streams; i++) { |
198 | 190 |
if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO && videoStream<0) { |
199 | 191 |
videoStream=i; |
... | ... | |
212 | 204 |
exit(-1); |
213 | 205 |
} |
214 | 206 |
|
215 |
// Get a pointer to the codec context for the video stream |
|
207 |
// Get a pointer to the codec context for the input video stream
|
|
216 | 208 |
pCodecCtx=pFormatCtx->streams[videoStream]->codec; |
217 | 209 |
pCodec = avcodec_find_decoder(pCodecCtx->codec_id); |
210 |
//extract W and H |
|
211 |
fprintf(stderr, "INIT: Width:%d Height:%d\n", pCodecCtx->width, pCodecCtx->height); |
|
218 | 212 |
|
219 |
fprintf(stderr, "INIT: Width:%d Height:%d\n",pCodecCtx->width,pCodecCtx->height); |
|
220 |
|
|
221 |
if(audioStream!=-1) { |
|
213 |
// Get a pointer to the codec context for the input audio stream |
|
214 |
if(audioStream != -1) { |
|
222 | 215 |
aCodecCtx=pFormatCtx->streams[audioStream]->codec; |
223 | 216 |
fprintf(stderr, "INIT: AUDIO Codecid: %d channels %d samplerate %d\n", aCodecCtx->codec_id, aCodecCtx->channels, aCodecCtx->sample_rate); |
224 | 217 |
} |
225 | 218 |
|
219 |
//setup video output encoder |
|
226 | 220 |
pCodecCtxEnc=avcodec_alloc_context(); |
227 | 221 |
#ifdef H264_VIDEO_ENCODER |
228 | 222 |
pCodecCtxEnc->me_range=16; |
... | ... | |
255 | 249 |
#endif |
256 | 250 |
fprintf(stderr, "INIT: VIDEO timebase OUT:%d %d IN: %d %d\n", pCodecCtxEnc->time_base.num, pCodecCtxEnc->time_base.den, pCodecCtx->time_base.num, pCodecCtx->time_base.den); |
257 | 251 |
|
252 |
// Find the decoder for the video stream |
|
253 |
#ifdef H264_VIDEO_ENCODER |
|
254 |
fprintf(stderr, "INIT: Setting VIDEO codecID to H264: %d %d\n",pCodecCtx->codec_id, CODEC_ID_H264); |
|
255 |
pCodecEnc = avcodec_find_encoder(CODEC_ID_H264);//pCodecCtx->codec_id); |
|
256 |
#else |
|
257 |
fprintf(stderr, "INIT: Setting VIDEO codecID to mpeg4: %d %d\n",pCodecCtx->codec_id, CODEC_ID_MPEG4); |
|
258 |
pCodecEnc = avcodec_find_encoder(CODEC_ID_MPEG4); |
|
259 |
#endif |
|
260 |
if(pCodec==NULL) { |
|
261 |
fprintf(stderr, "INIT: Unsupported IN VIDEO pcodec!\n"); |
|
262 |
return -1; // Codec not found |
|
263 |
} |
|
264 |
if(pCodecEnc==NULL) { |
|
265 |
fprintf(stderr, "INIT: Unsupported OUT VIDEO pcodecenc!\n"); |
|
266 |
return -1; // Codec not found |
|
267 |
} |
|
268 |
if(avcodec_open(pCodecCtx, pCodec)<0) { |
|
269 |
fprintf(stderr, "INIT: could not open IN VIDEO codec\n"); |
|
270 |
return -1; // Could not open codec |
|
271 |
} |
|
272 |
if(avcodec_open(pCodecCtxEnc, pCodecEnc)<0) { |
|
273 |
fprintf(stderr, "INIT: could not open OUT VIDEO codecEnc\n"); |
|
274 |
return -1; // Could not open codec |
|
275 |
} |
|
258 | 276 |
|
277 |
|
|
278 |
//setup audio output encoder |
|
259 | 279 |
aCodecCtxEnc = avcodec_alloc_context(); |
260 | 280 |
aCodecCtxEnc->bit_rate = audio_bitrate; //256000 |
261 | 281 |
aCodecCtxEnc->sample_fmt = SAMPLE_FMT_S16; |
262 | 282 |
aCodecCtxEnc->sample_rate = aCodecCtx->sample_rate; |
263 | 283 |
aCodecCtxEnc->channels = aCodecCtx->channels; |
264 |
//fprintf(stderr, "InitAUDIOFRAMESIZE:%d %d\n",aCodecCtxEnc->frame_size,av_rescale(44100,1,25)); |
|
265 | 284 |
fprintf(stderr, "INIT: AUDIO bitrate OUT:%d sample_rate:%d channels:%d\n", aCodecCtxEnc->bit_rate, aCodecCtxEnc->sample_rate, aCodecCtxEnc->channels); |
266 | 285 |
|
267 |
// Find the decoder for the video stream |
|
268 |
|
|
286 |
// Find the decoder for the audio stream |
|
269 | 287 |
if(audioStream!=-1) { |
270 | 288 |
aCodec = avcodec_find_decoder(aCodecCtx->codec_id); |
271 | 289 |
#ifdef MP3_AUDIO_ENCODER |
... | ... | |
290 | 308 |
fprintf(stderr, "INIT: could not open OUT AUDIO codec\n"); |
291 | 309 |
return -1; // Could not open codec |
292 | 310 |
} |
293 |
|
|
294 |
} |
|
295 |
#ifdef H264_VIDEO_ENCODER |
|
296 |
fprintf(stderr, "INIT: Setting VIDEO codecID to H264: %d %d\n",pCodecCtx->codec_id, CODEC_ID_H264); |
|
297 |
pCodecEnc = avcodec_find_encoder(CODEC_ID_H264);//pCodecCtx->codec_id); |
|
298 |
#else |
|
299 |
fprintf(stderr, "INIT: Setting VIDEO codecID to mpeg4: %d %d\n",pCodecCtx->codec_id, CODEC_ID_MPEG4); |
|
300 |
pCodecEnc = avcodec_find_encoder(CODEC_ID_MPEG4); |
|
301 |
#endif |
|
302 |
if(pCodec==NULL) { |
|
303 |
fprintf(stderr, "INIT: Unsupported IN VIDEO pcodec!\n"); |
|
304 |
return -1; // Codec not found |
|
305 |
} |
|
306 |
if(pCodecEnc==NULL) { |
|
307 |
fprintf(stderr, "INIT: Unsupported OUT VIDEO pcodecenc!\n"); |
|
308 |
return -1; // Codec not found |
|
309 | 311 |
} |
310 |
if(avcodec_open(pCodecCtx, pCodec)<0) { |
|
311 |
fprintf(stderr, "INIT: could not open IN VIDEO codec\n"); |
|
312 |
return -1; // Could not open codec |
|
312 |
|
|
313 |
// Allocate audio in and out buffers |
|
314 |
samples = (int16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); |
|
315 |
if(samples == NULL) { |
|
316 |
fprintf(stderr, "INIT: Memory error alloc audio samples!!!\n"); |
|
317 |
return -1; |
|
313 | 318 |
} |
314 |
if(avcodec_open(pCodecCtxEnc, pCodecEnc)<0) { |
|
315 |
fprintf(stderr, "INIT: could not open OUT VIDEO codecEnc\n"); |
|
316 |
return -1; // Could not open codec |
|
319 |
audio_outbuf_size = STREAMER_MAX_AUDIO_BUFFER_SIZE; |
|
320 |
audio_outbuf = av_malloc(audio_outbuf_size); |
|
321 |
if(audio_outbuf == NULL) { |
|
322 |
fprintf(stderr, "INIT: Memory error alloc audio_outbuf!!!\n"); |
|
323 |
return -1; |
|
317 | 324 |
} |
318 | 325 |
|
319 |
// Allocate video frame
|
|
326 |
// Allocate video in frame and out buffer
|
|
320 | 327 |
pFrame=avcodec_alloc_frame(); |
321 | 328 |
if(pFrame==NULL) { |
322 | 329 |
fprintf(stderr, "INIT: Memory error alloc video frame!!!\n"); |
323 | 330 |
return -1; |
324 | 331 |
} |
325 |
|
|
326 |
i=0; |
|
327 |
outbuf_size = 100000; |
|
328 |
outbuf = malloc(outbuf_size); |
|
329 |
if(!outbuf) { |
|
330 |
fprintf(stderr, "INIT: Memory error alloc outbuf!!!\n"); |
|
332 |
video_outbuf_size = STREAMER_MAX_VIDEO_BUFFER_SIZE; |
|
333 |
video_outbuf = av_malloc(video_outbuf_size); |
|
334 |
if(!video_outbuf) { |
|
335 |
fprintf(stderr, "INIT: Memory error alloc video_outbuf!!!\n"); |
|
331 | 336 |
return -1; |
332 | 337 |
} |
338 |
|
|
339 |
//allocate Napa-Wine transport |
|
333 | 340 |
frame = (Frame *)malloc(sizeof(Frame)); |
334 | 341 |
if(!frame) { |
335 | 342 |
fprintf(stderr, "INIT: Memory error alloc Frame!!!\n"); |
336 | 343 |
return -1; |
337 | 344 |
} |
338 |
sizeFrame = 3*sizeof(int32_t)+sizeof(struct timeval); |
|
339 | 345 |
chunk = (ExternalChunk *)malloc(sizeof(ExternalChunk)); |
340 | 346 |
if(!chunk) { |
341 | 347 |
fprintf(stderr, "INIT: Memory error alloc chunk!!!\n"); |
342 | 348 |
return -1; |
343 | 349 |
} |
344 |
sizeChunk = 6*sizeof(int32_t)+2*sizeof(struct timeval)+sizeof(double); |
|
345 |
chunk->data=NULL; |
|
350 |
|
|
351 |
//init an empty first video chunk |
|
352 |
chunk->data=NULL; |
|
346 | 353 |
initChunk(chunk, &seq_current_chunk); |
347 | 354 |
#ifdef DEBUG_CHUNKER |
348 | 355 |
fprintf(stderr, "INIT: chunk video %d\n", chunk->seq); |
349 | 356 |
#endif |
357 |
//init empty first audio chunk |
|
350 | 358 |
chunkaudio = (ExternalChunk *)malloc(sizeof(ExternalChunk)); |
351 | 359 |
if(!chunkaudio) { |
352 | 360 |
fprintf(stderr, "INIT: Memory error alloc chunkaudio!!!\n"); |
353 | 361 |
return -1; |
354 | 362 |
} |
355 |
chunkaudio->data=NULL;
|
|
363 |
chunkaudio->data=NULL; |
|
356 | 364 |
initChunk(chunkaudio, &seq_current_chunk); |
357 | 365 |
#ifdef DEBUG_CHUNKER |
358 | 366 |
fprintf(stderr, "INIT: chunk audio %d\n", chunkaudio->seq); |
359 | 367 |
#endif |
360 |
//av_init_packet(&packet); |
|
361 | 368 |
|
362 | 369 |
/* initialize the HTTP chunk pusher */ |
363 | 370 |
initChunkPusher(); //TRIPLO |
364 | 371 |
|
372 |
// i=0; |
|
365 | 373 |
|
374 |
//main loop to read from the input file |
|
366 | 375 |
while(av_read_frame(pFormatCtx, &packet)>=0) { |
367 | 376 |
// Is this a packet from the video stream? |
368 | 377 |
if(packet.stream_index==videoStream) { |
369 |
// Decode video frame
|
|
378 |
//decode the video packet into a raw pFrame
|
|
370 | 379 |
if(avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet)>0) { |
371 | 380 |
#ifdef DEBUG_VIDEO_FRAMES |
372 | 381 |
fprintf(stderr, "-------VIDEO FRAME type %d\n", pFrame->pict_type); |
... | ... | |
387 | 396 |
else { |
388 | 397 |
if(packet.dts!=AV_NOPTS_VALUE) { |
389 | 398 |
delta_video = packet.dts-last_pkt_dts; |
390 |
/* |
|
391 |
DeltaTimeVideo=((double)packet.dts-(double)last_pkt_dts)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate)); |
|
392 |
if(DeltaTimeVideo<0) DeltaTimeVideo=10; |
|
393 |
if(DeltaTimeVideo>80) DeltaTimeVideo=80; |
|
394 |
*/ |
|
395 | 399 |
last_pkt_dts = packet.dts; |
396 | 400 |
} |
397 | 401 |
else if(delta_video==0) |
... | ... | |
401 | 405 |
#ifdef DEBUG_VIDEO_FRAMES |
402 | 406 |
fprintf(stderr, "VIDEO: deltavideo : %d\n", (int)delta_video); |
403 | 407 |
#endif |
404 |
out_size = avcodec_encode_video(pCodecCtxEnc, outbuf, outbuf_size, pFrame);
|
|
408 |
video_frame_size = avcodec_encode_video(pCodecCtxEnc, video_outbuf, video_outbuf_size, pFrame);
|
|
405 | 409 |
#ifdef DEBUG_VIDEO_FRAMES |
406 | 410 |
fprintf(stderr, "VIDEO: original codec frame number %d\n", pCodecCtx->frame_number); |
407 | 411 |
fprintf(stderr, "VIDEO: duration %d timebase %d %d container timebase %d\n", (int)packet.duration, pCodecCtxEnc->time_base.den, pCodecCtxEnc->time_base.num, pCodecCtx->time_base.den); |
... | ... | |
425 | 429 |
#endif |
426 | 430 |
} |
427 | 431 |
if(frame->number>0) { |
428 |
//if(ptsaudio1>0) |
|
429 |
//use audio-based timestamps when available (both for video and audio frames) |
|
430 |
//newTime = (((double)target_pts-ptsaudio1)*1000.0*((double)av_q2d(pFormatCtx->streams[audioStream]->time_base)));//*(double)delta_audio; |
|
431 |
//else |
|
432 |
newTime = ((double)target_pts-ptsvideo1)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate)); |
|
432 |
newTime = ((double)target_pts-ptsvideo1)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate)); |
|
433 | 433 |
} |
434 | 434 |
} |
435 | 435 |
else //live source |
... | ... | |
449 | 449 |
if(frame->number>0) { |
450 | 450 |
newTime = ((double)target_pts-ptsvideo1)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate)); |
451 | 451 |
} |
452 |
//this was for on-the-fly timestamping |
|
453 |
//newTime=Now-StartTime; |
|
454 | 452 |
} |
455 | 453 |
#ifdef DEBUG_VIDEO_FRAMES |
456 | 454 |
fprintf(stderr, "VIDEO: NEWTIMESTAMP %ld\n", newTime); |
... | ... | |
464 | 462 |
|
465 | 463 |
frame->timestamp.tv_sec = (long long)newTime/1000; |
466 | 464 |
frame->timestamp.tv_usec = newTime%1000; |
467 |
|
|
468 |
frame->size = out_size; |
|
465 |
frame->size = video_frame_size; |
|
469 | 466 |
frame->type = pFrame->pict_type; |
470 | 467 |
#ifdef DEBUG_VIDEO_FRAMES |
471 | 468 |
fprintf(stderr, "VIDEO: encapsulated frame num:%d size:%d type:%d\n", frame->number, frame->size, frame->type); |
472 | 469 |
fprintf(stderr, "VIDEO: timestamped sec %d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec); |
473 |
//fprintf(stderr, "out_size:%d outbuf_size:%d packet.size:%d\n",out_size,outbuf_size,packet.size); |
|
474 |
#endif |
|
475 |
// Save the frame to disk |
|
476 |
//++i; |
|
477 |
//SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height, i); |
|
478 |
//HINT on malloc |
|
479 |
chunk->data = (uint8_t *)realloc(chunk->data, sizeof(uint8_t)*(chunk->payload_len+out_size+sizeFrame)); |
|
480 |
if(!chunk->data) { |
|
481 |
fprintf(stderr, "Memory error in chunk!!!\n"); |
|
482 |
return -1; |
|
483 |
} |
|
484 |
chunk->frames_num++; // number of frames in the current chunk |
|
485 |
//lets increase the numbering of the frames |
|
486 |
contFrameVideo++; |
|
487 |
#ifdef DEBUG_VIDEO_FRAMES |
|
488 |
//fprintf(stderr, "rialloco data di dim:%d con nuova dim:%d\n",chunk->payload_len,out_size); |
|
489 | 470 |
#endif |
471 |
contFrameVideo++; //lets increase the numbering of the frames |
|
490 | 472 |
|
491 |
tempdata = chunk->data+chunk->payload_len; |
|
492 |
*((int32_t *)tempdata) = frame->number; |
|
493 |
tempdata+=sizeof(int32_t); |
|
494 |
*((struct timeval *)tempdata) = frame->timestamp; |
|
495 |
tempdata+=sizeof(struct timeval); |
|
496 |
*((int32_t *)tempdata) = frame->size; |
|
497 |
tempdata+=sizeof(int32_t); |
|
498 |
*((int32_t *)tempdata) = frame->type; |
|
499 |
tempdata+=sizeof(int32_t); |
|
500 |
|
|
501 |
memcpy(chunk->data+chunk->payload_len+sizeFrame,outbuf,out_size); // insert new data |
|
502 |
chunk->payload_len += out_size + sizeFrame; // update payload length |
|
503 |
//fprintf(stderr, "outsize:%d payload_len:%d\n",out_size,chunk->payload_len); |
|
504 |
chunk->len = sizeChunk+chunk->payload_len ; // update overall length |
|
505 |
|
|
506 |
if(((int)frame->timestamp.tv_sec < (int)chunk->start_time.tv_sec) || ((int)frame->timestamp.tv_sec==(int)chunk->start_time.tv_sec && (int)frame->timestamp.tv_usec < (int)chunk->start_time.tv_usec) || (int)chunk->start_time.tv_sec==-1) { |
|
507 |
chunk->start_time.tv_sec = frame->timestamp.tv_sec; |
|
508 |
chunk->start_time.tv_usec = frame->timestamp.tv_usec; |
|
473 |
if(update_chunk(chunk, frame, video_outbuf) == -1) { |
|
474 |
fprintf(stderr, "VIDEO: unable to update chunk %d. Exiting.\n", chunk->seq); |
|
475 |
exit(-1); |
|
509 | 476 |
} |
510 |
if(((int)frame->timestamp.tv_sec > (int)chunk->end_time.tv_sec) || ((int)frame->timestamp.tv_sec==(int)chunk->end_time.tv_sec && (int)frame->timestamp.tv_usec > (int)chunk->end_time.tv_usec) || (int)chunk->end_time.tv_sec==-1) { |
|
511 |
chunk->end_time.tv_sec = frame->timestamp.tv_sec; |
|
512 |
chunk->end_time.tv_usec = frame->timestamp.tv_usec; |
|
513 |
} |
|
514 |
|
|
477 |
|
|
515 | 478 |
if(chunkFilled(chunk, cmeta)) { // is chunk filled using current strategy? |
516 | 479 |
//SAVE ON FILE |
517 | 480 |
//saveChunkOnFile(chunk); |
... | ... | |
527 | 490 |
} |
528 | 491 |
} |
529 | 492 |
else if(packet.stream_index==audioStream) { |
530 |
data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; |
|
531 |
if(avcodec_decode_audio3(aCodecCtx, audio_buf, &data_size, &packet)>0) { |
|
493 |
audio_data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; |
|
494 |
//decode the audio packet into a raw audio source buffer |
|
495 |
if(avcodec_decode_audio3(aCodecCtx, samples, &audio_data_size, &packet)>0) { |
|
532 | 496 |
#ifdef DEBUG_AUDIO_FRAMES |
533 | 497 |
fprintf(stderr, "\n-------AUDIO FRAME\n"); |
534 | 498 |
fprintf(stderr, "AUDIO: newTimeaudioSTART : %lf\n", (double)(packet.pts)*av_q2d(pFormatCtx->streams[audioStream]->time_base)); |
535 | 499 |
#endif |
536 |
if(data_size>0) { |
|
500 |
if(audio_data_size>0) {
|
|
537 | 501 |
#ifdef DEBUG_AUDIO_FRAMES |
538 |
fprintf(stderr, "AUDIO: datasizeaudio:%d\n", data_size); |
|
502 |
fprintf(stderr, "AUDIO: datasizeaudio:%d\n", audio_data_size);
|
|
539 | 503 |
#endif |
540 | 504 |
/* if a frame has been decoded, output it */ |
541 |
//fwrite(audio_buf, 1, data_size, outfileaudio);
|
|
505 |
//fwrite(samples, 1, audio_data_size, outfileaudio);
|
|
542 | 506 |
} |
543 | 507 |
else |
544 | 508 |
continue; |
545 | 509 |
|
546 |
audio_size = avcodec_encode_audio(aCodecCtxEnc,outbuf_audio,data_size,audio_buf);
|
|
510 |
audio_frame_size = avcodec_encode_audio(aCodecCtxEnc, audio_outbuf, audio_data_size, samples);
|
|
547 | 511 |
frame->number = contFrameAudio; |
548 | 512 |
|
549 | 513 |
if(frame->number==0) { |
... | ... | |
555 | 519 |
else { |
556 | 520 |
if(packet.dts!=AV_NOPTS_VALUE) { |
557 | 521 |
delta_audio = packet.dts-last_pkt_dts_audio; |
558 |
/* |
|
559 |
DeltaTimeAudio=(((double)packet.dts-last_pkt_dts_audio)*1000.0*((double)av_q2d(pFormatCtx->streams[audioStream]->time_base))); |
|
560 |
if(DeltaTimeAudio<0) DeltaTimeAudio=10; |
|
561 |
if(DeltaTimeAudio>1500) DeltaTimeAudio=1500; |
|
562 |
*/ |
|
563 | 522 |
last_pkt_dts_audio = packet.dts; |
564 | 523 |
} |
565 | 524 |
else if(delta_audio==0) |
... | ... | |
612 | 571 |
} |
613 | 572 |
|
614 | 573 |
if(frame->number>0) { |
615 |
//if(ptsaudio1>0) |
|
616 |
//use audio-based timestamps when available (both for video and audio frames) |
|
617 | 574 |
newTime = (((double)target_pts-ptsaudio1)*1000.0*((double)av_q2d(pFormatCtx->streams[audioStream]->time_base)));//*(double)delta_audio; |
618 |
//else |
|
619 |
// newTime = ((double)target_pts-ptsvideo1)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate)); |
|
620 | 575 |
} |
621 |
//this was for on-the-fly timestamping |
|
622 |
//newTime=Now-StartTime; |
|
623 | 576 |
} |
624 | 577 |
#ifdef DEBUG_AUDIO_FRAMES |
625 | 578 |
fprintf(stderr, "AUDIO: NEWTIMESTAMP %d\n", newTime); |
... | ... | |
633 | 586 |
|
634 | 587 |
frame->timestamp.tv_sec = (unsigned int)newTime/1000; |
635 | 588 |
frame->timestamp.tv_usec = newTime%1000; |
589 |
frame->size = audio_frame_size; |
|
590 |
frame->type = 5; // 5 is audio type |
|
636 | 591 |
#ifdef DEBUG_AUDIO_FRAMES |
637 | 592 |
fprintf(stderr, "AUDIO: pts %d duration %d timebase %d %d dts %d\n", (int)packet.pts, (int)packet.duration, pFormatCtx->streams[audioStream]->time_base.num, pFormatCtx->streams[audioStream]->time_base.den, (int)packet.dts); |
638 | 593 |
fprintf(stderr, "AUDIO: timestamp sec:%d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec); |
639 | 594 |
fprintf(stderr, "AUDIO: deltaaudio %lld\n", delta_audio); |
640 | 595 |
#endif |
641 |
|
|
642 |
frame->size = audio_size; |
|
643 |
frame->type = 5; // 5 is audio type |
|
644 |
|
|
645 |
chunkaudio->data = (uint8_t *)realloc(chunkaudio->data,sizeof(uint8_t)*(chunkaudio->payload_len+audio_size+sizeFrame)); |
|
646 |
if(!chunkaudio->data) { |
|
647 |
fprintf(stderr, "Memory error AUDIO chunk!!!\n"); |
|
648 |
return -1; |
|
649 |
} |
|
650 |
chunkaudio->frames_num++; // number of frames in the current chunk |
|
651 | 596 |
contFrameAudio++; |
652 |
tempdata = chunkaudio->data+chunkaudio->payload_len; |
|
653 |
*((int32_t *)tempdata) = frame->number; |
|
654 |
tempdata+=sizeof(int32_t); |
|
655 |
*((struct timeval *)tempdata) = frame->timestamp; |
|
656 |
tempdata+=sizeof(struct timeval); |
|
657 |
*((int32_t *)tempdata) = frame->size; |
|
658 |
tempdata+=sizeof(int32_t); |
|
659 |
*((int32_t *)tempdata) = frame->type; |
|
660 |
tempdata+=sizeof(int32_t); |
|
661 |
|
|
662 |
memcpy(chunkaudio->data+chunkaudio->payload_len+sizeFrame,outbuf_audio,audio_size); |
|
663 |
chunkaudio->payload_len += audio_size + sizeFrame; // update payload length |
|
664 |
//fprintf(stderr, "outsize:%d payload_len:%d\n",out_size,chunk->payload_len); |
|
665 |
chunkaudio->len = sizeChunk+chunkaudio->payload_len ; // update overall length |
|
666 |
|
|
667 |
if(((int)frame->timestamp.tv_sec < (int)chunkaudio->start_time.tv_sec) || ((int)frame->timestamp.tv_sec==(int)chunkaudio->start_time.tv_sec && (int)frame->timestamp.tv_usec < (int)chunkaudio->start_time.tv_usec) || (int)chunkaudio->start_time.tv_sec==-1) { |
|
668 |
chunkaudio->start_time.tv_sec = frame->timestamp.tv_sec; |
|
669 |
chunkaudio->start_time.tv_usec = frame->timestamp.tv_usec; |
|
670 |
} |
|
671 |
if(((int)frame->timestamp.tv_sec > (int)chunkaudio->end_time.tv_sec) || ((int)frame->timestamp.tv_sec==(int)chunkaudio->end_time.tv_sec && (int)frame->timestamp.tv_usec > (int)chunkaudio->end_time.tv_usec) || (int)chunkaudio->end_time.tv_sec==-1) { |
|
672 |
chunkaudio->end_time.tv_sec = frame->timestamp.tv_sec; |
|
673 |
chunkaudio->end_time.tv_usec = frame->timestamp.tv_usec; |
|
674 |
} |
|
675 | 597 |
|
598 |
if(update_chunk(chunkaudio, frame, audio_outbuf) == -1) { |
|
599 |
fprintf(stderr, "AUDIO: unable to update chunk %d. Exiting.\n", chunkaudio->seq); |
|
600 |
exit(-1); |
|
601 |
} |
|
676 | 602 |
//set priority |
677 | 603 |
chunkaudio->priority = 1; |
678 | 604 |
|
... | ... | |
715 | 641 |
free(chunk); |
716 | 642 |
free(chunkaudio); |
717 | 643 |
free(frame); |
718 |
free(outbuf);
|
|
719 |
free(outbuf_audio);
|
|
644 |
av_free(video_outbuf);
|
|
645 |
av_free(audio_outbuf);
|
|
720 | 646 |
free(cmeta); |
721 | 647 |
|
722 | 648 |
// Free the YUV frame |
723 | 649 |
av_free(pFrame); |
724 |
av_free(audio_buf);
|
|
650 |
av_free(samples);
|
|
725 | 651 |
|
726 | 652 |
// Close the codec |
727 | 653 |
avcodec_close(pCodecCtx); |
... | ... | |
736 | 662 |
av_close_input_file(pFormatCtx); |
737 | 663 |
return 0; |
738 | 664 |
} |
665 |
|
|
666 |
|
|
667 |
int update_chunk(ExternalChunk *chunk, Frame *frame, uint8_t *outbuf) { |
|
668 |
static int sizeFrameHeader = 3*sizeof(int32_t)+sizeof(struct timeval); |
|
669 |
static int sizeChunkHeader = 6*sizeof(int32_t)+2*sizeof(struct timeval)+sizeof(double); |
|
670 |
|
|
671 |
//moving temp pointer to encode Frame on the wire |
|
672 |
uint8_t *tempdata = NULL; |
|
673 |
|
|
674 |
//HINT on malloc |
|
675 |
chunk->data = (uint8_t *)realloc(chunk->data, sizeof(uint8_t)*(chunk->payload_len + frame->size + sizeFrameHeader)); |
|
676 |
if(!chunk->data) { |
|
677 |
fprintf(stderr, "Memory error in chunk!!!\n"); |
|
678 |
return -1; |
|
679 |
} |
|
680 |
chunk->frames_num++; // number of frames in the current chunk |
|
681 |
|
|
682 |
//package the Frame header |
|
683 |
tempdata = chunk->data+chunk->payload_len; |
|
684 |
*((int32_t *)tempdata) = frame->number; |
|
685 |
tempdata+=sizeof(int32_t); |
|
686 |
*((struct timeval *)tempdata) = frame->timestamp; |
|
687 |
tempdata+=sizeof(struct timeval); |
|
688 |
*((int32_t *)tempdata) = frame->size; |
|
689 |
tempdata+=sizeof(int32_t); |
|
690 |
*((int32_t *)tempdata) = frame->type; |
|
691 |
tempdata+=sizeof(int32_t); |
|
692 |
|
|
693 |
//insert the new frame data |
|
694 |
memcpy(chunk->data + chunk->payload_len + sizeFrameHeader, outbuf, frame->size); |
|
695 |
chunk->payload_len += frame->size + sizeFrameHeader; // update payload length |
|
696 |
chunk->len = sizeChunkHeader + chunk->payload_len; // update overall length |
|
697 |
|
|
698 |
//update timestamps |
|
699 |
if(((int)frame->timestamp.tv_sec < (int)chunk->start_time.tv_sec) || ((int)frame->timestamp.tv_sec==(int)chunk->start_time.tv_sec && (int)frame->timestamp.tv_usec < (int)chunk->start_time.tv_usec) || (int)chunk->start_time.tv_sec==-1) { |
|
700 |
chunk->start_time.tv_sec = frame->timestamp.tv_sec; |
|
701 |
chunk->start_time.tv_usec = frame->timestamp.tv_usec; |
|
702 |
} |
|
703 |
|
|
704 |
if(((int)frame->timestamp.tv_sec > (int)chunk->end_time.tv_sec) || ((int)frame->timestamp.tv_sec==(int)chunk->end_time.tv_sec && (int)frame->timestamp.tv_usec > (int)chunk->end_time.tv_usec) || (int)chunk->end_time.tv_sec==-1) { |
|
705 |
chunk->end_time.tv_sec = frame->timestamp.tv_sec; |
|
706 |
chunk->end_time.tv_usec = frame->timestamp.tv_usec; |
|
707 |
} |
|
708 |
return 0; |
|
709 |
} |
|
710 |
|
Also available in: Unified diff