Revision e11386c0 chunker_streamer/chunker_streamer.c

View differences:

chunker_streamer/chunker_streamer.c
9 9

  
10 10

  
11 11
#include "chunker_streamer.h"
12
#include <signal.h>
13
#include <math.h>
14
#include <getopt.h>
15
#include <libswscale/swscale.h>
12 16

  
17
#define STREAMER_MAX(a,b) ((a>b)?(a):(b))
18
#define STREAMER_MIN(a,b) ((a<b)?(a):(b))
13 19

  
14 20
//#define DEBUG_AUDIO_FRAMES
15 21
//#define DEBUG_VIDEO_FRAMES
16 22
//#define DEBUG_CHUNKER
17 23
#define DEBUG_ANOMALIES
18
//#define DEBUG_TIMESTAMPING
19

  
20
#define MAX(a,b) ((a>b)?(a):(b))
24
//~ #define DEBUG_TIMESTAMPING
25
#define GET_PSNR(x) ((x==0) ? 0 : (-10.0*log(x)/log(10)))
21 26

  
22 27
ChunkerMetadata *cmeta = NULL;
23 28
int seq_current_chunk = 1; //chunk numbering starts from 1; HINT do i need more bytes?
24 29

  
30
#define AUDIO_CHUNK 0
31
#define VIDEO_CHUNK 1
32

  
33
void SaveFrame(AVFrame *pFrame, int width, int height);
34
void SaveEncodedFrame(Frame* frame, uint8_t *video_outbuf);
35
int video_record_count = 0;
36
int savedVideoFrames = 0;
37
long int firstSavedVideoFrame = 0;
38
ChunkerStreamerTestMode = 0;
25 39

  
26
int chunkFilled(ExternalChunk *echunk, ChunkerMetadata *cmeta) {
27
	// different strategies to implement
28
	if(cmeta->strategy == 0) { // number of frames per chunk constant
40
// Constant number of frames per chunk
41
int chunkFilledFramesStrategy(ExternalChunk *echunk, int chunkType)
42
{
29 43
#ifdef DEBUG_CHUNKER
30
		fprintf(stderr, "CHUNKER: check if frames num %d == %d in chunk %d\n", echunk->frames_num, cmeta->val_strategy, echunk->seq);
44
	fprintf(stderr, "CHUNKER: check if frames num %d == %d in chunk %d\n", echunk->frames_num, cmeta->framesPerChunk[chunkType], echunk->seq);
31 45
#endif
32
		if(echunk->frames_num == cmeta->val_strategy)
33
			return 1;
34
  }
35
	
36
	if(cmeta->strategy == 1) // constant size. Note that for now each chunk will have a size just greater or equal than the required value - It can be considered as constant size. If that is not good we need to change the code. Also, to prevent too low values of strategy_val. This choice is more robust
37
		if(echunk->payload_len >= cmeta->val_strategy)
38
			return 1;
46
	if(echunk->frames_num == cmeta->framesPerChunk[chunkType])
47
		return 1;
48

  
49
	return 0;
50
}
51

  
52
// Constant size. Note that for now each chunk will have a size just greater or equal than the required value
53
// It can be considered as constant size.
54
int chunkFilledSizeStrategy(ExternalChunk *echunk, int chunkType)
55
{
56
#ifdef DEBUG_CHUNKER
57
	fprintf(stderr, "CHUNKER: check if chunk size %d >= %d in chunk %d\n", echunk->payload_len, cmeta->targetChunkSize, echunk->seq);
58
#endif
59
	if(echunk->payload_len >= cmeta->targetChunkSize)
60
		return 1;
39 61
	
40 62
	return 0;
41 63
}
42 64

  
65
// Performace optimization.
66
// The chunkFilled function has been splitted into two functions (one for each strategy).
67
// Instead of continuously check the strategy flag (which is constant),
68
// we change the callback just once according to the current strategy (look at the switch statement in the main in which this function pointer is set)
69
int (*chunkFilled)(ExternalChunk *echunk, int chunkType);
43 70

  
44 71
void initChunk(ExternalChunk *chunk, int *seq_num) {
45 72
	chunk->seq = (*seq_num)++;
......
58 85
	chunk->_refcnt = 0;
59 86
}
60 87

  
88
int quit = 0;
89

  
90
void sigproc()
91
{
92
	printf("you have pressed ctrl-c, terminating...\n");
93
	quit = 1;
94
}
95

  
96
static void print_usage(int argc, char *argv[])
97
{
98
  fprintf (stderr,
99
    "\nUsage:%s [options]\n"
100
    "\n"
101
    "Mandatory options:\n"
102
    "\t[-i input file]\n"
103
    "\t[-a audio bitrate]\n"
104
    "\t[-v video bitrate]\n\n"
105
    "Other options:\n"
106
    "\t[-s WxH]: force video size.\n"
107
    "\t[-l]: this is a live stream.\n"
108
    "\t[-o]: adjust av frames timestamps.\n"
109
    "\t[-t]: QoE test mode\n\n"
110
    "=======================================================\n", argv[0]
111
    );
112
  }
61 113

  
62 114
int main(int argc, char *argv[]) {
115
	signal(SIGINT, sigproc);
116
	
63 117
	int i=0;
64 118

  
65 119
	//output variables
......
76 130
	int len1;
77 131
	int frameFinished;
78 132
	//frame sequential counters
79
	int contFrameAudio=1, contFrameVideo=1;
133
	int contFrameAudio=1, contFrameVideo=0;
80 134
	int numBytes;
81 135

  
82 136
	//command line parameters
83
	int audio_bitrate;
84
	int video_bitrate;
137
	int audio_bitrate = -1;
138
	int video_bitrate = -1;
85 139
	int live_source = 0; //tells to sleep before reading next frame in not live (i.e. file)
86 140
	int offset_av = 0; //tells to compensate for offset between audio and video in the file
87 141
	
......
89 143
	int16_t *samples = NULL;
90 144
	//a raw uncompressed video picture
91 145
	AVFrame *pFrame = NULL;
146
	AVFrame *scaledFrame = NULL;
92 147

  
93 148
	AVFormatContext *pFormatCtx;
94 149
	AVCodecContext  *pCodecCtx,*pCodecCtxEnc,*aCodecCtxEnc,*aCodecCtx;
......
109 164
	Frame *frame = NULL;
110 165
	ExternalChunk *chunk = NULL;
111 166
	ExternalChunk *chunkaudio = NULL;
112

  
113

  
114
	//scan the command line
115
	if(argc < 4) {
116
		fprintf(stderr, "execute ./chunker_streamer moviefile audiobitrate videobitrate <live source flag (0 or 1)> <offset av flag (0 or 1)>\n");
167
	
168
	char av_input[1024];
169
	int dest_width = -1;
170
	int dest_height = -1;
171
	
172
	static struct option long_options[] =
173
	{
174
		/* These options set a flag. */
175
		{"long_option", required_argument, 0, 0},
176
		{0, 0, 0, 0}
177
	};
178
	/* `getopt_long' stores the option index here. */
179
	int option_index = 0, c;
180
	int mandatories = 0;
181
	while ((c = getopt_long (argc, argv, "i:a:v:s:lot", long_options, &option_index)) != -1)
182
	{
183
		switch (c) {
184
			case 0: //for long options
185
				break;
186
			case 'i':
187
				sprintf(av_input, "%s", optarg);
188
				mandatories++;
189
				break;
190
			case 'a':
191
				sscanf(optarg, "%d", &audio_bitrate);
192
				mandatories++;
193
				break;
194
			case 'v':
195
				sscanf(optarg, "%d", &video_bitrate);
196
				mandatories++;
197
				break;
198
			case 's':
199
				sscanf(optarg, "%dx%d", &dest_width, &dest_height);
200
				break;
201
			case 'l':
202
				live_source = 1;
203
				break;
204
			case 'o':
205
				offset_av = 1;
206
				break;
207
			case 't':
208
				ChunkerStreamerTestMode = 1;
209
				break;
210
			default:
211
				print_usage(argc, argv);
212
				return -1;
213
		}
214
	}
215
	
216
	if(mandatories < 3) 
217
	{
218
		print_usage(argc, argv);
117 219
		return -1;
118 220
	}
119
	sscanf(argv[2],"%d", &audio_bitrate);
120
	sscanf(argv[3],"%d", &video_bitrate);
121
	if(argc>=5) sscanf(argv[4],"%d", &live_source);
122
	if(argc==6) sscanf(argv[5],"%d", &offset_av);
221

  
222
#ifdef YUV_RECORD_ENABLED
223
	if(ChunkerStreamerTestMode)
224
	{
225
		DELETE_DIR("yuv_data");
226
		CREATE_DIR("yuv_data");
227
		//FILE* pFile=fopen("yuv_data/streamer_out.yuv", "w");
228
		//fclose(pFile);
229
	}
230
#endif
123 231

  
124 232
restart:
125 233
	// read the configuration file
126 234
	cmeta = chunkerInit();
235
	switch(cmeta->strategy)
236
	{
237
		case 1:
238
			chunkFilled = chunkFilledSizeStrategy;
239
			break;
240
		default:
241
			chunkFilled = chunkFilledFramesStrategy;
242
	}
243
		
127 244
	if(live_source)
128 245
		fprintf(stderr, "INIT: Using LIVE SOURCE TimeStamps\n");
129 246
	if(offset_av)
......
133 250
	av_register_all();
134 251

  
135 252
	// Open input file
136
	if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL) != 0) {
253
	if(av_open_input_file(&pFormatCtx, av_input, NULL, 0, NULL) != 0) {
137 254
		fprintf(stdout, "INIT: Couldn't open video file. Exiting.\n");
138 255
		exit(-1);
139 256
	}
......
145 262
	}
146 263

  
147 264
	// Dump information about file onto standard error
148
	dump_format(pFormatCtx, 0, argv[1], 0);
265
	dump_format(pFormatCtx, 0, av_input, 0);
149 266

  
150 267
	// Find the video and audio stream numbers
151 268
	for(i=0; i<pFormatCtx->nb_streams; i++) {
......
190 307
	pCodecCtxEnc->codec_id   = CODEC_ID_H264;//13;//pCodecCtx->codec_id;
191 308
	pCodecCtxEnc->bit_rate = video_bitrate;///400000;
192 309
	// resolution must be a multiple of two 
193
	pCodecCtxEnc->width = pCodecCtx->width;
194
	pCodecCtxEnc->height = pCodecCtx->height;
310
	pCodecCtxEnc->width = (dest_width > 0) ? dest_width : pCodecCtx->width;
311
	pCodecCtxEnc->height = (dest_height > 0) ? dest_height : pCodecCtx->height;
195 312
	// frames per second 
196 313
	pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
197 314
	pCodecCtxEnc->gop_size = 100; // emit one intra frame every ten frames 
......
202 319
//	pCodecCtxEnc->rc_min_rate = 0;
203 320
//	pCodecCtxEnc->rc_max_rate = 0;
204 321
//	pCodecCtxEnc->rc_buffer_size = 0;
205
//	pCodecCtxEnc->flags |= CODEC_FLAG_PSNR;
322
	pCodecCtxEnc->flags |= CODEC_FLAG_PSNR;
206 323
//	pCodecCtxEnc->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_P4X4 | X264_PART_B8X8;
207 324
//	pCodecCtxEnc->crf = 0.0f;
325
	
326
#ifdef STREAMER_X264_USE_SSIM
327
	pCodecCtxEnc->flags2 |= CODEC_FLAG2_SSIM;
328
#endif
329

  
330
	pCodecCtxEnc->weighted_p_pred=2; //maps wpredp=2; weighted prediction analysis method
331
	// pCodecCtxEnc->rc_min_rate = 0;
332
	// pCodecCtxEnc->rc_max_rate = video_bitrate*2;
333
	// pCodecCtxEnc->rc_buffer_size = 0;
208 334
#else
209 335
	pCodecCtxEnc->codec_type = CODEC_TYPE_VIDEO;
210 336
	pCodecCtxEnc->codec_id   = CODEC_ID_MPEG4;
211 337
	pCodecCtxEnc->bit_rate = video_bitrate;
338
	//~ pCodecCtxEnc->qmin = 30;
339
	//~ pCodecCtxEnc->qmax = 30;
212 340
	//times 20 follows the defaults, was not needed in previous versions of libavcodec
213 341
	pCodecCtxEnc->bit_rate_tolerance = video_bitrate*20;
214 342
//	pCodecCtxEnc->crf = 20.0f;
215
	pCodecCtxEnc->width = pCodecCtx->width;
216
	pCodecCtxEnc->height = pCodecCtx->height;
343
	pCodecCtxEnc->width = (dest_width > 0) ? dest_width : pCodecCtx->width;
344
	pCodecCtxEnc->height = (dest_height > 0) ? dest_height : pCodecCtx->height;
217 345
	// frames per second 
218
	pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
219
	pCodecCtxEnc->gop_size = 100; // emit one intra frame every ten frames 
346
	//~ pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
347
	//printf("pCodecCtx->time_base=%d/%d\n", pCodecCtx->time_base.num, pCodecCtx->time_base.den);
348
	pCodecCtxEnc->time_base= (AVRational){1,25};
349
	pCodecCtxEnc->gop_size = 12; // emit one intra frame every twelve frames 
220 350
	//pCodecCtxEnc->max_b_frames=1;
221 351
	pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
352
	pCodecCtxEnc->flags = CODEC_FLAG_PSNR;
353
	//~ pCodecCtxEnc->flags |= CODEC_FLAG_QSCALE;
222 354
#endif
223 355

  
224 356
	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);
......
302 434

  
303 435
	// Allocate video in frame and out buffer
304 436
	pFrame=avcodec_alloc_frame();
305
	if(pFrame==NULL) {
437
	scaledFrame=avcodec_alloc_frame();
438
	if(pFrame==NULL || scaledFrame == NULL) {
306 439
		fprintf(stderr, "INIT: Memory error alloc video frame!!!\n");
307 440
		return -1;
308 441
	}
309 442
	video_outbuf_size = STREAMER_MAX_VIDEO_BUFFER_SIZE;
310 443
	video_outbuf = av_malloc(video_outbuf_size);
311
	if(!video_outbuf) {
444
	int scaledFrame_buf_size = avpicture_get_size( PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height);
445
	uint8_t* scaledFrame_buffer = (uint8_t *) av_malloc( scaledFrame_buf_size * sizeof( uint8_t ) );
446
	avpicture_fill( (AVPicture*) scaledFrame, scaledFrame_buffer, PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height);
447
	if(!video_outbuf || !scaledFrame_buffer) {
312 448
		fprintf(stderr, "INIT: Memory error alloc video_outbuf!!!\n");
313 449
		return -1;
314 450
	}
......
353 489
	long long lateTime = 0;
354 490
	long long maxAudioInterval = 0;
355 491
	long long maxVDecodeTime = 0;
492
	unsigned char lastIFrameDistance = 0;
493

  
494
#ifdef TCPIO
495
	static char peer_ip[16];
496
	static int peer_port;
497
	int res = sscanf(cmeta->outside_world_url, "tcp://%15[0-9.]:%d", peer_ip, &peer_port);
498
	if (res < 2) {
499
		fprintf(stderr,"error parsing output url: %s\n", cmeta->outside_world_url);
500
		return -2;
501
	}
502
	
503
	initTCPPush(peer_ip, peer_port);
504
#endif
505
	
506
	char videotrace_filename[255];
507
	char psnr_filename[255];
508
	sprintf(videotrace_filename, "yuv_data/videotrace.log");
509
	sprintf(psnr_filename, "yuv_data/psnrtrace.log");
510
	FILE* videotrace = fopen(videotrace_filename, "w");
511
	FILE* psnrtrace = fopen(psnr_filename, "w");
356 512

  
357 513
	//main loop to read from the input file
358
	while(av_read_frame(pFormatCtx, &packet)>=0)
514
	while((av_read_frame(pFormatCtx, &packet)>=0) && !quit)
359 515
	{
360 516
		//detect if a strange number of anomalies is occurring
361 517
		if(ptsvideo1 < 0 || ptsvideo1 > packet.dts || ptsaudio1 < 0 || ptsaudio1 > packet.dts) {
......
375 531
			}
376 532
		}
377 533

  
534
		//newTime_video and _audio are in usec
535
		//if video and audio stamps differ more than 5sec
536
		if( newTime_video - newTime_audio > 5000000 || newTime_video - newTime_audio < -5000000 ) {
537
			newtime_anomalies_counter++;
538
#ifdef DEBUG_ANOMALIES
539
			fprintf(stderr, "READLOOP: NEWTIME audio video differ anomaly detected number %d\n", newtime_anomalies_counter);
540
#endif
541
		}
542

  
378 543
		if(newtime_anomalies_counter > 50) { //just a random threshold
379 544
			if(live_source) { //restart just in case of live source
380 545
#ifdef DEBUG_ANOMALIES
......
389 554
		{
390 555
			if(!live_source)
391 556
			{
392
			if(audioStream != -1) { //take this "time bank" method into account only if we have audio track
393
				// lateTime < 0 means a positive time account that can be used to decode video frames
394
				// if (lateTime + maxVDecodeTime) >= 0 then we may have a negative time account after video transcoding
395
				// therefore, it's better to skip the frame
396
				if((lateTime+maxVDecodeTime) >= 0)
397
				{
557
				if(audioStream != -1) { //take this "time bank" method into account only if we have audio track
558
					// lateTime < 0 means a positive time account that can be used to decode video frames
559
					// if (lateTime + maxVDecodeTime) >= 0 then we may have a negative time account after video transcoding
560
					// therefore, it's better to skip the frame
561
					if((lateTime+maxVDecodeTime) >= 0)
562
					{
398 563
#ifdef DEBUG_ANOMALIES
399
					fprintf(stderr, "\n\n\t\t************************* SKIPPING VIDEO FRAME ***********************************\n\n", sleep);
564
						fprintf(stderr, "\n\n\t\t************************* SKIPPING VIDEO FRAME ***********************************\n\n", sleep);
400 565
#endif
401
					continue;
566
						continue;
567
					}
402 568
				}
403 569
			}
404
			}
405 570
			
406 571
			gettimeofday(&tmp_tv, NULL);
407 572
			
......
413 578
				fprintf(stderr, "\n-------VIDEO FRAME type %d\n", pFrame->pict_type);
414 579
				fprintf(stderr, "VIDEO: dts %lld pts %lld\n", packet.dts, packet.pts);
415 580
#endif
416
				if(frameFinished) { // it must be true all the time else error
417
					frame->number = contFrameVideo;
581
				if(frameFinished)
582
				{ // it must be true all the time else error
583
				
584
					frame->number = ++contFrameVideo;
585

  
586
#ifdef VIDEO_DEINTERLACE
587
					avpicture_deinterlace(
588
						(AVPicture*) pFrame,
589
						(const AVPicture*) pFrame,
590
						pCodecCtxEnc->pix_fmt,
591
						pCodecCtxEnc->width,
592
						pCodecCtxEnc->height);
593
#endif
594

  
418 595
#ifdef DEBUG_VIDEO_FRAMES
419 596
					fprintf(stderr, "VIDEO: finished frame %d dts %lld pts %lld\n", frame->number, packet.dts, packet.pts);
420 597
#endif
421 598
					if(frame->number==0) {
422 599
						if(packet.dts==AV_NOPTS_VALUE)
600
						{
423 601
							//a Dts with a noPts value is troublesome case for delta calculation based on Dts
602
							contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
424 603
							continue;
604
						}
425 605
						last_pkt_dts = packet.dts;
426 606
						newTime = 0;
427 607
					}
......
431 611
							last_pkt_dts = packet.dts;
432 612
						}
433 613
						else if(delta_video==0)
614
						{
434 615
							//a Dts with a noPts value is troublesome case for delta calculation based on Dts
616
							contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
435 617
							continue;
618
						}
436 619
					}
437 620
#ifdef DEBUG_VIDEO_FRAMES
438 621
					fprintf(stderr, "VIDEO: deltavideo : %d\n", (int)delta_video);
439 622
#endif
440
					video_frame_size = avcodec_encode_video(pCodecCtxEnc, video_outbuf, video_outbuf_size, pFrame);
623

  
624
					if(pCodecCtx->height != pCodecCtxEnc->height || pCodecCtx->width != pCodecCtxEnc->width)
625
					{
626
						static AVPicture pict;
627
						static struct SwsContext *img_convert_ctx = NULL;
628
						
629
						if(img_convert_ctx == NULL)
630
						{
631
							img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
632
							if(img_convert_ctx == NULL) {
633
								fprintf(stderr, "Cannot initialize the conversion context!\n");
634
								exit(1);
635
							}
636
						}
637
						sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, scaledFrame->data, scaledFrame->linesize);
638
						video_frame_size = avcodec_encode_video(pCodecCtxEnc, video_outbuf, video_outbuf_size, scaledFrame);
639
					}
640
					else
641
						video_frame_size = avcodec_encode_video(pCodecCtxEnc, video_outbuf, video_outbuf_size, pFrame);
642
					
441 643
					if(video_frame_size <= 0)
644
					{
645
						contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
442 646
						continue;
443
#ifdef DEBUG_VIDEO_FRAMES
444
					fprintf(stderr, "VIDEO: original codec frame number %d vs. encoded %d vs. packed %d\n", pCodecCtx->frame_number, pCodecCtxEnc->frame_number, frame->number);
445
					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);
446
#endif
647
					}
447 648

  
448 649
					//use pts if dts is invalid
449 650
					if(packet.dts!=AV_NOPTS_VALUE)
......
451 652
					else if(packet.pts!=AV_NOPTS_VALUE)
452 653
						target_pts = packet.pts;
453 654
					else
655
					{
656
						contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
454 657
						continue;
658
					}
455 659

  
456 660
					if(!offset_av)
457 661
					{
......
492 696
						fprintf(stderr, "VIDEO: SKIPPING FRAME\n");
493 697
#endif
494 698
						newtime_anomalies_counter++;
699
#ifdef DEBUG_ANOMALIES
700
						fprintf(stderr, "READLOOP: NEWTIME negative video timestamp anomaly detected number %d\n", newtime_anomalies_counter);
701
#endif
702
						contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
495 703
						continue; //SKIP THIS FRAME, bad timestamp
496 704
					}
705
					
706
					//~ printf("pCodecCtxEnc->error[0]=%lld\n", pFrame->error[0]);
497 707
	
498 708
					frame->timestamp.tv_sec = (long long)newTime/1000;
499 709
					frame->timestamp.tv_usec = newTime%1000;
500 710
					frame->size = video_frame_size;
501 711
					/* pict_type maybe 1 (I), 2 (P), 3 (B), 5 (AUDIO)*/
502
					frame->type = pFrame->pict_type;
712
					frame->type = (unsigned char)pFrame->pict_type;
713

  
714
#ifdef H264_VIDEO_ENCODER
715

  
716
#ifdef STREAMER_X264_USE_SSIM
717
					/*double ssim_y = x264_context->enc->stat.frame.f_ssim
718
                      / (((x264_context->enc->param.i_width-6)>>2) * ((x264_context->enc->param.i_height-6)>>2));*/
719
#else
720
					//fprintf(psnrtrace, "%f\n", (float)x264_psnr( x264_context->enc->stat.frame.i_ssd[0], x264_context->enc->param.i_width * x264_context->enc->param.i_height ));
721
					//frame->psnr = (uint16_t) ((float)(STREAMER_MIN(x264_psnr( x264_context->enc->stat.frame.i_ssd[0], x264_context->enc->param.i_width * x264_context->enc->param.i_height ),MAX_PSNR))*65536/MAX_PSNR);
722
#endif
723

  
724
#else
725
					//psnr = (uint16_t) ((float)(STREAMER_MIN(GET_PSNR(pCodecCtxEnc->error[0]/(pCodecCtxEnc->width*pCodecCtxEnc->height*255.0*255.0)),MAX_PSNR))*65536/MAX_PSNR);
726
					//pCodecCtxEnc->error[0] = 0;
727
#endif
728

  
729
#ifdef DEBUG_VIDEO_FRAMES
730
					fprintf(stderr, "VIDEO: original codec frame number %d vs. encoded %d vs. packed %d\n", pCodecCtx->frame_number, pCodecCtxEnc->frame_number, frame->number);
731
					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);
732
#endif
733

  
734
#ifdef YUV_RECORD_ENABLED
735
					if(ChunkerStreamerTestMode)
736
					{
737
						if(videotrace)
738
							fprintf(videotrace, "%d %d %d\n", frame->number, pFrame->pict_type, frame->size);
739

  
740
						if(pCodecCtx->height != pCodecCtxEnc->height || pCodecCtx->width != pCodecCtxEnc->width)
741
							SaveFrame(scaledFrame, pCodecCtxEnc->width, pCodecCtxEnc->height);
742
						else
743
							SaveFrame(pFrame, pCodecCtxEnc->width, pCodecCtxEnc->height);
744

  
745
						++savedVideoFrames;
746
						SaveEncodedFrame(frame, video_outbuf);
747

  
748
						if(!firstSavedVideoFrame)
749
							firstSavedVideoFrame = frame->number;
750
						
751
						char tmp_filename[255];
752
						sprintf(tmp_filename, "yuv_data/streamer_out_context.txt");
753
						FILE* tmp = fopen(tmp_filename, "w");
754
						if(tmp)
755
						{
756
							fprintf(tmp, "width = %d\nheight = %d\ntotal_frames_saved = %d\ntotal_frames_decoded = %d\nfirst_frame_number = %d\nlast_frame_number = %d\n"
757
								,pCodecCtxEnc->width, pCodecCtxEnc->height
758
								,savedVideoFrames, savedVideoFrames, firstSavedVideoFrame, frame->number);
759
							fclose(tmp);
760
						}
761
					}
762
#endif
763

  
503 764
#ifdef DEBUG_VIDEO_FRAMES
504 765
					fprintf(stderr, "VIDEO: encapsulated frame size:%d type:%d\n", frame->size, frame->type);
505 766
					fprintf(stderr, "VIDEO: timestamped sec %d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
506 767
#endif
507
					contFrameVideo++; //lets increase the numbering of the frames
768
					//contFrameVideo++; //lets increase the numbering of the frames
508 769

  
509 770
					if(update_chunk(chunk, frame, video_outbuf) == -1) {
510 771
						fprintf(stderr, "VIDEO: unable to update chunk %d. Exiting.\n", chunk->seq);
511 772
						exit(-1);
512 773
					}
513 774

  
514
					if(chunkFilled(chunk, cmeta)) { // is chunk filled using current strategy?
775
					if(chunkFilled(chunk, VIDEO_CHUNK)) { // is chunk filled using current strategy?
515 776
						//SAVE ON FILE
516 777
						//saveChunkOnFile(chunk);
517 778
						//Send the chunk via http to an external transport/player
779
#ifdef HTTPIO
518 780
						pushChunkHttp(chunk, cmeta->outside_world_url);
781
#endif
782
#ifdef TCPIO
783
						pushChunkTcp(chunk);
784
#endif
519 785
#ifdef DEBUG_CHUNKER
520 786
						fprintf(stderr, "VIDEO: sent chunk video %d\n", chunk->seq);
521 787
#endif
......
667 933
					fprintf(stderr, "AUDIO: SKIPPING FRAME\n");
668 934
#endif
669 935
					newtime_anomalies_counter++;
936
#ifdef DEBUG_ANOMALIES
937
					fprintf(stderr, "READLOOP: NEWTIME negative audio timestamp anomaly detected number %d\n", newtime_anomalies_counter);
938
#endif
670 939
					continue; //SKIP THIS FRAME, bad timestamp
671 940
				}
672 941

  
......
688 957
				//set priority
689 958
				chunkaudio->priority = 1;
690 959

  
691
				if(chunkFilled(chunkaudio, cmeta)) {
960
				if(chunkFilled(chunkaudio, AUDIO_CHUNK)) {
692 961
					// is chunk filled using current strategy?
693 962
					//SAVE ON FILE
694 963
					//saveChunkOnFile(chunkaudio);
......
736 1005
					newTime_prev = newTime_audio;
737 1006
					gettimeofday(&lastAudioSent, NULL);
738 1007
				}
739

  
740 1008
			}
741 1009
		}
742 1010
		else {
......
746 1014
			av_free_packet(&packet);
747 1015
		}
748 1016
	}
1017
	
1018
	if(videotrace)
1019
		fclose(videotrace);
1020
	if(psnrtrace)
1021
		fclose(psnrtrace);
749 1022

  
750 1023
close:
751 1024
	if(chunk->seq != 0 && chunk->frames_num>0) {
......
769 1042
		chunkaudio->seq = 0; //signal that we need an increase just in case we will restart
770 1043
	}
771 1044

  
1045
#ifdef HTTPIO
772 1046
	/* finalize the HTTP chunk pusher */
773 1047
	finalizeChunkPusher();
1048
#elif TCPIO
1049
	finalizeTCPChunkPusher();
1050
#endif
774 1051

  
775 1052
	free(chunk);
776 1053
	free(chunkaudio);
777 1054
	free(frame);
778 1055
	av_free(video_outbuf);
1056
	av_free(scaledFrame_buffer);
779 1057
	av_free(audio_outbuf);
780 1058
	free(cmeta);
781 1059

  
782 1060
	// Free the YUV frame
783 1061
	av_free(pFrame);
1062
	av_free(scaledFrame);
784 1063
	av_free(samples);
785 1064
  
786 1065
	// Close the codec
......
819 1098
		last_pkt_dts_audio=0;
820 1099
		target_pts=0;
821 1100
		i=0;
1101
		//~ contFrameVideo = 0;
1102
		//~ contFrameAudio = 1;
1103
		
1104
#ifdef YUV_RECORD_ENABLED
1105
		if(ChunkerStreamerTestMode)
1106
		{
1107
			video_record_count++;
1108
			//~ savedVideoFrames = 0;
1109
			
1110
			//~ char tmp_filename[255];
1111
			//~ sprintf(tmp_filename, "yuv_data/out_%d.yuv", video_record_count);
1112
			//~ FILE *pFile=fopen(tmp_filename, "w");
1113
			//~ if(pFile!=NULL)
1114
				//~ fclose(pFile);
1115
		}
1116
#endif
1117

  
822 1118
		goto restart;
823 1119
	}
824 1120

  
825 1121
	return 0;
826 1122
}
827 1123

  
828

  
829 1124
int update_chunk(ExternalChunk *chunk, Frame *frame, uint8_t *outbuf) {
830 1125
	//the frame.h gets encoded into 5 slots of 32bits (3 ints plus 2 more for the timeval struct
831 1126
	static int sizeFrameHeader = 5*sizeof(int32_t);
......
884 1179
	return 0;
885 1180
}
886 1181

  
1182
void SaveFrame(AVFrame *pFrame, int width, int height)
1183
{
1184
	FILE *pFile;
1185
	int  y;
1186

  
1187
	 // Open file
1188
	char tmp_filename[255];
1189
	sprintf(tmp_filename, "yuv_data/streamer_out.yuv");
1190
	pFile=fopen(tmp_filename, "ab");
1191
	if(pFile==NULL)
1192
		return;
1193

  
1194
	// Write header
1195
	//fprintf(pFile, "P5\n%d %d\n255\n", width, height);
1196
  
1197
	// Write Y data
1198
	for(y=0; y<height; y++)
1199
  		if(fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width, pFile) != width)
1200
		{
1201
			printf("errno = %d\n", errno);
1202
			exit(1);
1203
		}
1204
	// Write U data
1205
	for(y=0; y<height/2; y++)
1206
  		if(fwrite(pFrame->data[1]+y*pFrame->linesize[1], 1, width/2, pFile) != width/2)
1207
  		{
1208
			printf("errno = %d\n", errno);
1209
			exit(1);
1210
		}
1211
	// Write V data
1212
	for(y=0; y<height/2; y++)
1213
  		if(fwrite(pFrame->data[2]+y*pFrame->linesize[2], 1, width/2, pFile) != width/2)
1214
  		{
1215
			printf("errno = %d\n", errno);
1216
			exit(1);
1217
		}
1218
  
1219
	// Close file
1220
	fclose(pFile);
1221
}
1222

  
1223
void SaveEncodedFrame(Frame* frame, uint8_t *video_outbuf)
1224
{
1225
	static FILE* pFile = NULL;
1226
	
1227
	pFile=fopen("yuv_data/streamer_out.mpeg4", "ab");
1228
	fwrite(frame, sizeof(Frame), 1, pFile);
1229
	fwrite(video_outbuf, frame->size, 1, pFile);
1230
	fclose(pFile);
1231
}

Also available in: Unified diff