Revision c3031a67

View differences:

chunker_streamer/chunker_streamer.c
25 25
	ExternalChunk *chunk;
26 26
	AVCodecContext *pCodecCtxEnc;
27 27
};
28
struct outstream outstream[4];
28
#define QUALITYLEVELS_MAX 9
29
struct outstream outstream[1+QUALITYLEVELS_MAX+1];
30
int qualitylevels = 3;
31
int indexchannel = 1;
29 32

  
30 33
#define DEBUG
31 34
#define DEBUG_AUDIO_FRAMES  false
......
145 148
    "\t[--video_stream]:set video_stream ID in input\n"
146 149
    "\t[--audio_stream]:set audio_stream ID in input\n"
147 150
    "\t[--avfilter]:set input filter (default: yadif\n"
151
    "\t[--no-indexchannel]: turn off generation of index channel\n"
152
    "\t[--qualitylevels]:set number of quality levels\n"
148 153
    "\n"
149 154
    "Codec options:\n"
150 155
    "\t[-g GOP]: gop size\n"
......
496 501
int main(int argc, char *argv[]) {
497 502
	signal(SIGINT, sigproc);
498 503
	
499
	int i=0;
504
	int i=0,j,k;
500 505

  
501 506
	//output variables
502 507
	uint8_t *video_outbuf = NULL;
......
557 562
		{"audio_stream", required_argument, 0, 0},
558 563
		{"video_stream", required_argument, 0, 0},
559 564
		{"avfilter", required_argument, 0, 0},
565
		{"indexchannel", no_argument, &indexchannel, 1},
566
		{"no-indexchannel", no_argument, &indexchannel, 0},
567
		{"qualitylevels", required_argument, 0, 'Q'},
560 568
		{0, 0, 0, 0}
561 569
	};
562 570
	/* `getopt_long' stores the option index here. */
563 571
	int option_index = 0, c;
564 572
	int mandatories = 0;
565
	while ((c = getopt_long (argc, argv, "i:a:v:A:V:s:lop:q:tF:g:b:d:x:", long_options, &option_index)) != -1)
573
	while ((c = getopt_long (argc, argv, "i:a:v:A:V:s:lop:q:tF:g:b:d:x:Q:", long_options, &option_index)) != -1)
566 574
	{
567 575
		switch (c) {
568 576
			case 0: //for long options
......
621 629
			case 'x':
622 630
				codec_options = strdup(optarg);
623 631
				break;
632
			case 'Q':
633
				sscanf(optarg, "%d", &qualitylevels);
634
				if (qualitylevels > QUALITYLEVELS_MAX) {
635
					fprintf(stderr,"Too many quality levels: %d (max:%d)\n", qualitylevels, QUALITYLEVELS_MAX);
636
					return -1;
637
				}
638
				break;
624 639
			default:
625 640
				print_usage(argc, argv);
626 641
				return -1;
......
651 666
		fprintf(stderr,"error parsing output url: %s\n", outside_world_url);
652 667
		return -2;
653 668
	}
654
	
655
	outstream[0].output = initTCPPush(peer_ip, peer_port);
656
	if (!outstream[0].output) {
657
		fprintf(stderr, "Error initializing output module, exiting\n");
658
		exit(1);
659
	}
660
	outstream[1].output = initTCPPush(peer_ip, peer_port+1);
661
	if (!outstream[1].output) {
662
		fprintf(stderr, "Error initializing output module, exiting\n");
663
		exit(1);
664
	}
665
	outstream[2].output = initTCPPush(peer_ip, peer_port+2);
666
	if (!outstream[2].output) {
667
		fprintf(stderr, "Error initializing output module, exiting\n");
668
		exit(1);
669
	}
670
	outstream[3].output = initTCPPush(peer_ip, peer_port+3);
671
	if (!outstream[3].output) {
672
		fprintf(stderr, "Error initializing output module, exiting\n");
673
		exit(1);
669

  
670
	for (i=0; i < 1 + qualitylevels + (indexchannel?1:0); i++) {
671
		outstream[i].output = initTCPPush(peer_ip, peer_port+i);
672
		if (!outstream[i].output) {
673
			fprintf(stderr, "Error initializing output module, exiting\n");
674
			exit(1);
675
		}
674 676
	}
675 677
#endif
676 678

  
......
749 751
	dest_width = (dest_width > 0) ? dest_width : pCodecCtx->width;
750 752
	dest_height = (dest_height > 0) ? dest_height : pCodecCtx->height;
751 753

  
752
	//create an empty first video chunk
753
	outstream[0].chunk = (ExternalChunk *)malloc(sizeof(ExternalChunk));
754
	if(!outstream[0].chunk) {
755
		fprintf(stderr, "INIT: Memory error alloc chunk!!!\n");
756
		return -1;
754
	//initialize outstream structures
755
	for (i=0; i < 1 + qualitylevels + (indexchannel?1:0); i++) {
756
		outstream[i].chunk = (ExternalChunk *)malloc(sizeof(ExternalChunk));
757
		if(!outstream[i].chunk) {
758
			fprintf(stderr, "INIT: Memory error alloc chunk!!!\n");
759
			return -1;
760
		}
761
		outstream[i].chunk->data = NULL;
762
		outstream[i].chunk->seq = 0;
763
		dcprintf(DEBUG_CHUNKER, "INIT: chunk video %d\n", outstream[i].chunk->seq);
764
		outstream[i].pCodecCtxEnc = NULL;
757 765
	}
758
	outstream[0].chunk->data = NULL;
759
	outstream[0].chunk->seq = 0;
760
	dcprintf(DEBUG_CHUNKER, "INIT: chunk video %d\n", outstream[0].chunk->seq);
761 766
	outstream[0].pCodecCtxEnc = NULL;
762

  
763
	outstream[1].chunk = (ExternalChunk *)malloc(sizeof(ExternalChunk));
764
	if(!outstream[1].chunk) {
765
		fprintf(stderr, "INIT: Memory error alloc chunk!!!\n");
766
		return -1;
767
	}
768
	outstream[1].chunk->data = NULL;
769
	outstream[1].chunk->seq = 0;
770
	dcprintf(DEBUG_CHUNKER, "INIT: chunk video %d\n", outstream[1].chunk->seq);
771
	outstream[1].pCodecCtxEnc = openVideoEncoder(video_codec, video_bitrate, dest_width, dest_height, pCodecCtx->time_base, codec_options);
772
	if (!outstream[1].pCodecCtxEnc) {
773
		return -1;
774
	}
775

  
776
	outstream[2].chunk = (ExternalChunk *)malloc(sizeof(ExternalChunk));
777
	if(!outstream[2].chunk) {
778
		fprintf(stderr, "INIT: Memory error alloc chunk!!!\n");
779
		return -1;
780
	}
781
	outstream[2].chunk->data = NULL;
782
	outstream[2].chunk->seq = 0;
783
	dcprintf(DEBUG_CHUNKER, "INIT: chunk video %d\n", outstream[2].chunk->seq);
784
	outstream[2].pCodecCtxEnc = openVideoEncoder(video_codec, video_bitrate/3, (dest_width/4)*2, (dest_height/4)*2, pCodecCtx->time_base, codec_options);	// (w/4)*2, since libx264 requires width,height to be even
785
	if (!outstream[2].pCodecCtxEnc) {
786
		return -1;
787
	}
788

  
789
	outstream[3].chunk = (ExternalChunk *)malloc(sizeof(ExternalChunk));
790
	if(!outstream[3].chunk) {
791
		fprintf(stderr, "INIT: Memory error alloc chunk!!!\n");
792
		return -1;
767
	for (i=1,j=1,k=1; i < 1 + qualitylevels; i++) {
768
		outstream[i].pCodecCtxEnc = openVideoEncoder(video_codec, video_bitrate/j, (dest_width/k/2)*2, (dest_height/k/2)*2, pCodecCtx->time_base, codec_options);	// (w/2)*2, since libx264 requires width,height to be even
769
		if (!outstream[i].pCodecCtxEnc) {
770
			return -1;
771
		}
772
		j*=3;	//reduce bitrate to 1/3
773
		k*=2;	//reduce dimensions to 1/2
793 774
	}
794
	outstream[3].chunk->data = NULL;
795
	outstream[3].chunk->seq = 0;
796
	dcprintf(DEBUG_CHUNKER, "INIT: chunk video %d\n", outstream[3].chunk->seq);
797
	outstream[3].pCodecCtxEnc = openVideoEncoder(video_codec, 50000, 160, 120, pCodecCtx->time_base, codec_options);	// (w/4)*2, since libx264 requires width,height to be even
798
	if (!outstream[3].pCodecCtxEnc) {
799
		return -1;
775
	if (indexchannel) {
776
		outstream[qualitylevels + 1].pCodecCtxEnc = openVideoEncoder(video_codec, 50000, 160, 120, pCodecCtx->time_base, codec_options);
777
		if (!outstream[qualitylevels + 1].pCodecCtxEnc) {
778
			return -1;
779
		}
800 780
	}
801 781

  
802 782
	fprintf(stderr, "INIT: VIDEO timebase OUT:%d %d IN: %d %d\n", outstream[1].pCodecCtxEnc->time_base.num, outstream[1].pCodecCtxEnc->time_base.den, pCodecCtx->time_base.num, pCodecCtx->time_base.den);
......
1038 1018
					// store timestamp in useconds for next frame sleep
1039 1019
					newTime_video = pts2ms(pFrame->pkt_pts - ptsvideo1, pFormatCtx->streams[videoStream]->time_base)*1000;
1040 1020

  
1041
					if(true) {
1021
					if(true) {	//copy channel
1042 1022
						video_frame_size = packet.size;
1043 1023
						if (video_frame_size > video_outbuf_size) {
1044 1024
							fprintf(stderr, "VIDEO: error, outbuf too small, SKIPPING\n");;
......
1057 1037
					            pFrame->pict_type);
1058 1038
						addFrameToOutstream(&outstream[0], frame, video_outbuf);
1059 1039
					}
1060
					if(true) {
1061
						video_frame_size = transcodeFrame(video_outbuf, video_outbuf_size, &target_pts, pFrame, pFormatCtx->streams[videoStream]->time_base, pCodecCtx, outstream[1].pCodecCtxEnc);
1040
					for (i=1; i < 1 + qualitylevels + (indexchannel?1:0); i++) {
1041
						video_frame_size = transcodeFrame(video_outbuf, video_outbuf_size, &target_pts, pFrame, pFormatCtx->streams[videoStream]->time_base, pCodecCtx, outstream[i].pCodecCtxEnc);
1062 1042
						if (video_frame_size <= 0) {
1063 1043
							av_free_packet(&packet);
1064 1044
							contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
1065 1045
							continue;
1066 1046
						}
1067
						createFrame(frame, pts2ms(target_pts - ptsvideo1, pFormatCtx->streams[videoStream]->time_base), video_frame_size, 
1068
					            (unsigned char)outstream[1].pCodecCtxEnc->coded_frame->pict_type);
1069
						addFrameToOutstream(&outstream[1], frame, video_outbuf);
1070
					}
1071
					if(true) {
1072
						video_frame_size = transcodeFrame(video_outbuf, video_outbuf_size, &target_pts, pFrame, pFormatCtx->streams[videoStream]->time_base, pCodecCtx, outstream[2].pCodecCtxEnc);
1073
						if (video_frame_size <= 0) {
1074
							av_free_packet(&packet);
1075
							contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
1076
							continue;
1077
						}
1078
						createFrame(frame, pts2ms(target_pts - ptsvideo1, pFormatCtx->streams[videoStream]->time_base), video_frame_size, 
1079
					            (unsigned char)outstream[2].pCodecCtxEnc->coded_frame->pict_type);
1080
						addFrameToOutstream(&outstream[2], frame, video_outbuf);
1081
					}
1082
					if(true) {
1083
						video_frame_size = transcodeFrame(video_outbuf, video_outbuf_size, &target_pts, pFrame, pFormatCtx->streams[videoStream]->time_base, pCodecCtx, outstream[3].pCodecCtxEnc);
1084
						if (video_frame_size <= 0) {
1085
							av_free_packet(&packet);
1086
							contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
1087
							continue;
1088
						}
1089
						createFrame(frame, pts2ms(target_pts - ptsvideo1, pFormatCtx->streams[videoStream]->time_base), video_frame_size, 
1090
					            (unsigned char)outstream[3].pCodecCtxEnc->coded_frame->pict_type);
1091
						addFrameToOutstream(&outstream[3], frame, video_outbuf);
1047
						createFrame(frame, pts2ms(target_pts - ptsvideo1, pFormatCtx->streams[videoStream]->time_base), video_frame_size,
1048
					            (unsigned char)outstream[i].pCodecCtxEnc->coded_frame->pict_type);
1049
						addFrameToOutstream(&outstream[i], frame, video_outbuf);
1092 1050
					}
1093 1051

  
1094 1052

  
......
1249 1207
					//SAVE ON FILE
1250 1208
					//saveChunkOnFile(chunkaudio);
1251 1209
					//Send the chunk to an external transport/player
1252
					sendChunk(outstream[0].output, chunkaudio);
1253
					sendChunk(outstream[1].output, chunkaudio);
1254
					sendChunk(outstream[2].output, chunkaudio);
1210
					for (i=0; i < 1 + qualitylevels; i++) {	//do not send audio to the index channel
1211
						sendChunk(outstream[i].output, chunkaudio);
1212
					}
1255 1213
					dctprintf(DEBUG_CHUNKER, "AUDIO: just sent chunk audio %d\n", chunkaudio->seq);
1256 1214
					chunkaudio->seq = 0; //signal that we need an increase
1257 1215
					//initChunk(chunkaudio, &seq_current_chunk);
......
1302 1260
		fclose(psnrtrace);
1303 1261

  
1304 1262
close:
1305
	if(outstream[0].chunk->seq != 0 && outstream[0].chunk->frames_num>0) {
1306
		//SAVE ON FILE
1307
		//saveChunkOnFile(chunk);
1308
		//Send the chunk to an external transport/player
1309
		sendChunk(outstream[0].output, outstream[0].chunk);
1310
		dcprintf(DEBUG_CHUNKER, "CHUNKER: SENDING LAST VIDEO CHUNK\n");
1311
		outstream[0].chunk->seq = 0; //signal that we need an increase just in case we will restart
1263
	for (i=0; i < 1 + qualitylevels + (indexchannel?1:0); i++) {
1264
		if(outstream[i].chunk->seq != 0 && outstream[i].chunk->frames_num>0) {
1265
			sendChunk(outstream[i].output, outstream[0].chunk);
1266
			dcprintf(DEBUG_CHUNKER, "CHUNKER: SENDING LAST VIDEO CHUNK\n");
1267
			outstream[i].chunk->seq = 0; //signal that we need an increase just in case we will restart
1268
		}
1312 1269
	}
1313
	if(chunkaudio->seq != 0 && chunkaudio->frames_num>0) {
1314
		//SAVE ON FILE     
1315
		//saveChunkOnFile(chunkaudio);
1316
		//Send the chunk via http to an external transport/player
1317
		sendChunk(outstream[0].output, chunkaudio);
1318
		dcprintf(DEBUG_CHUNKER, "CHUNKER: SENDING LAST AUDIO CHUNK\n");
1319
		chunkaudio->seq = 0; //signal that we need an increase just in case we will restart
1270
	for (i=0; i < 1 + qualitylevels; i++) {
1271
		if(chunkaudio->seq != 0 && chunkaudio->frames_num>0) {
1272
			sendChunk(outstream[i].output, chunkaudio);
1273
			dcprintf(DEBUG_CHUNKER, "CHUNKER: SENDING LAST AUDIO CHUNK\n");
1274
		}
1320 1275
	}
1276
	chunkaudio->seq = 0; //signal that we need an increase just in case we will restart
1321 1277

  
1322 1278
#ifdef HTTPIO
1323 1279
	/* finalize the HTTP chunk pusher */
1324 1280
	finalizeChunkPusher();
1325 1281
#endif
1326 1282

  
1327
	free(outstream[0].chunk);
1283
	for (i=0; i < 1 + qualitylevels + (indexchannel?1:0); i++) {
1284
		free(outstream[i].chunk);
1285
	}
1328 1286
	free(chunkaudio);
1329 1287
	free(frame);
1330 1288
	av_free(video_outbuf);
......
1337 1295
  
1338 1296
	// Close the codec
1339 1297
	avcodec_close(pCodecCtx);
1340
	avcodec_close(outstream[1].pCodecCtxEnc);
1341
	avcodec_close(outstream[2].pCodecCtxEnc);
1342
	avcodec_close(outstream[3].pCodecCtxEnc);
1298
	for (i=1; i < 1 + qualitylevels + (indexchannel?1:0); i++) {
1299
		avcodec_close(outstream[i].pCodecCtxEnc);
1300
	}
1343 1301

  
1344 1302
	if(audioStream!=-1) {
1345 1303
		avcodec_close(aCodecCtx);
......
1392 1350
	}
1393 1351

  
1394 1352
#ifdef TCPIO
1395
	finalizeTCPChunkPusher(outstream[0].output);
1396
	finalizeTCPChunkPusher(outstream[1].output);
1397
	finalizeTCPChunkPusher(outstream[2].output);
1398
	finalizeTCPChunkPusher(outstream[3].output);
1353
	for (i=0; i < 1 + qualitylevels + (indexchannel?1:0); i++) {
1354
		finalizeTCPChunkPusher(outstream[i].output);
1355
	}
1399 1356
#endif
1400 1357

  
1401 1358
#ifdef USE_AVFILTER

Also available in: Unified diff