Пример #1
0
int main(int argc, const char *argv[]) {
	//input parameters
	FNHOLDER(inputFilename);
	FNHOLDER(playlistFilename);
	baseDirName [MAX_FILENAME_LENGTH ]=0;
	baseFileName[MAX_FILENAME_LENGTH ]=0;
	currentOutputDirName[MAX_FILENAME_LENGTH ]=0;
	baseFileExtension[MAX_FILENAME_LENGTH ]=0;
	
	
	baseFileExtension[MAXT_EXT_LENGTH]=0; //either "ts", "aac" or "mp3"
	int segmentLength, quiet, version,usage;
	int ret;
	int listlen;
	int persist=0;
 

	FNHOLDER(tempPlaylistName);

	if ( parseCommandLine(argc, argv,inputFilename, playlistFilename, baseDirName, baseFileName, baseFileExtension, &segmentLength, &listlen, &quiet, &version,&usage,&persist) != 0)
		return 0;

	if (usage) printUsage();
	if (version) ffmpeg_version();
	if (version || usage) return 0;

	//fprintf(stderr, "Options parsed: inputFilename:%s playlistFilename:%s baseDirName:%s baseFileName:%s baseFileExtension:%s segmentLength:%d\n",inputFilename,playlistFilename,baseDirName,baseFileName,baseFileExtension,segmentLength );


	if (listlen>0){
		snprintf(tempPlaylistName, MAX_FILENAME_LENGTH, "%s/%s", baseDirName, playlistFilename);
		strncpy(playlistFilename, tempPlaylistName, MAX_FILENAME_LENGTH);
		snprintf(tempPlaylistName, MAX_FILENAME_LENGTH, "%s.tmp", playlistFilename);
	}

	ret = segment(inputFilename, baseDirName, playlistFilename, baseFileName, baseFileExtension, segmentLength, listlen);
	return ret;
}
Пример #2
0
int main(int argc, const char *argv[]) {
	//input parameters
	FNHOLDER(inputFilename);
	FNHOLDER(playlistFilename);
	baseDirName [MAX_FILENAME_LENGTH ]=0;
	baseFileName[MAX_FILENAME_LENGTH ]=0;
	currentOutputDirName[MAX_FILENAME_LENGTH ]=0;
	baseFileExtension[MAX_FILENAME_LENGTH ]=0;
	
	baseFileExtension[MAXT_EXT_LENGTH]=0; //either "ts", "aac" or "mp3"
	int segmentLength, quiet, version,usage;
 


	
	FNHOLDER(tempPlaylistName);


	//these are used to determine the exact length of the current segment
	double segment_start_time = 0;
	unsigned int actual_segment_durations[MAX_SEGMENTS+1];
	double packet_time = 0;

	unsigned int output_index = 1;
	AVOutputFormat *ofmt=NULL;
	AVFormatContext *ic = NULL;
	AVFormatContext *oc;
	AVStream *in_video_st = NULL;
	AVStream *in_audio_st = NULL;
	AVStream *out_video_st = NULL;
	AVStream *out_audio_st = NULL;
	AVCodec *codec;

	unsigned int num_segments = 0;

	int decode_done;
	int ret;
	int i;
	int listlen;
	int listofs=1;
	int persist=0;
	
	
	if ( parseCommandLine(argc, argv,inputFilename, playlistFilename, baseDirName, baseFileName, baseFileExtension, &segmentLength, &listlen, &quiet, &version,&usage,&persist) != 0)
		return 0;

	if (usage) printUsage();
	if (version) ffmpeg_version();
	if (version || usage) return 0;

	//fprintf(stderr, "Options parsed: inputFilename:%s playlistFilename:%s baseDirName:%s baseFileName:%s baseFileExtension:%s segmentLength:%d\n",inputFilename,playlistFilename,baseDirName,baseFileName,baseFileExtension,segmentLength );


	if (listlen>0){
		snprintf(tempPlaylistName, MAX_FILENAME_LENGTH, "%s/%s", baseDirName, playlistFilename);
		strncpy(playlistFilename, tempPlaylistName, MAX_FILENAME_LENGTH);
		snprintf(tempPlaylistName, MAX_FILENAME_LENGTH, "%s.tmp", playlistFilename);
	}

	//if (!quiet) av_log_set_level(AV_LOG_DEBUG);

	av_register_all();
	avformat_network_init(); //just to be safe with later version and be able to handle all kind of input urls
	
while(1) {
	ret = avformat_open_input(&ic, inputFilename, NULL, NULL);
	if (ret != 0) {
		if (persist) {
			sleep(1);
			continue;
		}
		fprintf(stderr, "Could not open input file %s. Error %d.\n", inputFilename, ret);
		exit(1);
	}

	if (avformat_find_stream_info(ic, NULL) < 0) {
		fprintf(stderr, "Could not read stream information.\n");
		if (persist){
			avformat_close_input(&ic);
			sleep(1);
			continue;
		}
		exit(1);
	}

	oc = avformat_alloc_context();
	if (!oc) {
		fprintf(stderr, "Could not allocate output context.");
		if (persist){
			avformat_close_input(&ic);
			sleep(1);
			continue;
		}
		exit(1);
	}

	int in_video_index = -1;
	int in_audio_index = -1;
	int out_video_index = -1;
	int out_audio_index = -1;

	for (i = 0; i < ic->nb_streams; i++) {
		switch (ic->streams[i]->codec->codec_type) {
			case AVMEDIA_TYPE_VIDEO:
				if (!out_video_st) {
					in_video_st=ic->streams[i];
					in_video_index = i;
					in_video_st->discard = AVDISCARD_NONE;
					out_video_st = add_output_stream(oc, in_video_st);
					out_video_index=out_video_st->index;
				}
				break;
			case AVMEDIA_TYPE_AUDIO:
				if (!out_audio_st) {
					in_audio_st=ic->streams[i];
					in_audio_index = i;
					in_audio_st->discard = AVDISCARD_NONE;
					out_audio_st = add_output_stream(oc, in_audio_st);
					out_audio_index=out_audio_st->index;
				}
				break;
			default:
				ic->streams[i]->discard = AVDISCARD_ALL;
				break;
		}
	}

	if (in_video_index == -1) {
		fprintf(stderr, "Source stream must have video component.\n");
		if (persist){
			avformat_close_input(&ic);
			avformat_free_context(oc);
			sleep(1);
			continue;
		}
		exit(1);
	}


	if (!ofmt) ofmt = av_guess_format("mpegts", NULL, NULL);
	if (!ofmt) {
		fprintf(stderr, "Could not find MPEG-TS muxer.\n");
		exit(1);
	}

	oc->oformat = ofmt;

	if (oc->oformat->flags & AVFMT_GLOBALHEADER) oc->flags |= CODEC_FLAG_GLOBAL_HEADER;
	
	av_dump_format(oc, 0, baseFileName, 1);


	codec = avcodec_find_decoder(in_video_st->codec->codec_id);
	if (!codec) {
		fprintf(stderr, "Could not find video decoder, key frames will not be honored.\n");
	}
	ret = avcodec_open2(in_video_st->codec, codec, NULL);
	if (ret < 0) {
		fprintf(stderr, "Could not open video decoder, key frames will not be honored.\n");
	}

	if (listlen>0){
		snprintf(currentOutputFileName, MAX_FILENAME_LENGTH, "%s/%s-%u%s", baseDirName, baseFileName, output_index, baseFileExtension);
	} else { //archive mode
		localtime_r_ex(&start_time);
		fillofn();
	}
	
	if (avio_open(&oc->pb, currentOutputFileName,AVIO_FLAG_WRITE) < 0) {
		fprintf(stderr, "Could not open '%s'.\n", currentOutputFileName);
		exit(1);
	} else if (!quiet) fprintf(stderr, "Starting segment '%s'\n", currentOutputFileName);

	int r = avformat_write_header(oc, NULL);
	if (r) {
		fprintf(stderr, "Could not write mpegts header to first output file.\n");
		debugReturnCode(r);
		exit(1);
	}


	int waitfirstpacket=1; 
	time_t first_frame_sec=time(NULL);
	
	int iskeyframe=0;     
	double vid_pts2time=(double)in_video_st->time_base.num / in_video_st->time_base.den;
	
	//double aud_pts2time=0;
	//if (in_audio_st)  aud_pts2time=(double)in_audio_st->time_base.num / in_audio_st->time_base.den;
	
	
	double prev_packet_time=0;
	do {
		AVPacket packet;

		decode_done = av_read_frame(ic, &packet);

		if (decode_done < 0) {
			break;
		}

		//a potential memory leak:
	//         if (av_dup_packet(&packet) < 0) {
	//             fprintf(stderr, "Could not duplicate packet.");
	//             av_packet_unref(&packet);
	//             break;
	//         }


		//get the most recent packet time
		//this time is used when the time for the final segment is printed. It may not be on the edge of
		//of a keyframe!
		if (packet.stream_index == in_video_index) {
			packet.stream_index = out_video_index;
			packet_time = (double) packet.pts * vid_pts2time;
			iskeyframe=packet.flags & AV_PKT_FLAG_KEY;
			if (iskeyframe && waitfirstpacket) {
				waitfirstpacket=0;
				prev_packet_time=packet_time;
				segment_start_time=packet_time;
				first_frame_sec=time(NULL);
			}
		} else if (packet.stream_index == in_audio_index){
			packet.stream_index = out_audio_index;
			iskeyframe=0;
		} else {
			//how this got here?!
			av_packet_unref(&packet);
			continue;
		}

		
		if (waitfirstpacket) {
			av_packet_unref(&packet);
			continue;
		}
		
		//start looking for segment splits for videos one half second before segment duration expires. This is because the 
		//segments are split on key frames so we cannot expect all segments to be split exactly equally. 
		if (iskeyframe &&  ((packet_time - segment_start_time) >= (segmentLength - 0.25)) &&  (time(NULL)!=first_frame_sec)) { //a keyframe  near or past segmentLength -> SPLIT
			avio_flush(oc->pb);
			avio_close(oc->pb);
			if (listlen>0){
				actual_segment_durations[num_segments] = (unsigned int) rint(prev_packet_time - segment_start_time);
				num_segments++;
				if (num_segments>listlen) { //move list to exclude last:
					snprintf(currentOutputFileName, MAX_FILENAME_LENGTH, "%s/%s-%u%s", baseDirName, baseFileName, listofs, baseFileExtension);
					unlink (currentOutputFileName);
					listofs++; num_segments--;
					memmove(actual_segment_durations,actual_segment_durations+1,num_segments*sizeof(actual_segment_durations[0]));
					
				}
				write_index_file(playlistFilename, tempPlaylistName, segmentLength, num_segments,actual_segment_durations, listofs,  baseFileName, baseFileExtension, (num_segments>=MAX_SEGMENTS));

				if (num_segments==MAX_SEGMENTS) {
					fprintf(stderr, "Reached \"hard\" max segment number %u. If this is not live stream increase segment duration. If live segmenting set max list lenth (-m ...)\n", MAX_SEGMENTS);
					break;
				}
				output_index++;
				snprintf(currentOutputFileName, MAX_FILENAME_LENGTH, "%s/%s-%u%s", baseDirName, baseFileName, output_index, baseFileExtension);
			} else { //archive mode:
				localtime_r_ex(&end_time);
				fixofn();
			}
			
			if (avio_open(&oc->pb, currentOutputFileName, AVIO_FLAG_WRITE) < 0) {
				fprintf(stderr, "Could not open '%s'\n", currentOutputFileName);
				break;
			} else if (!quiet) fprintf(stderr, "Starting segment '%s'\n", currentOutputFileName);
			fflush(stderr);
 			segment_start_time = packet_time;
			first_frame_sec=time(NULL);
		}
		if (packet.stream_index == out_video_index) prev_packet_time=packet_time;

		ret = av_write_frame(oc, &packet);

		if (ret < 0) {
			fprintf(stderr, "Warning: Could not write frame of stream.\n");
		} else if (ret > 0) {
			fprintf(stderr, "End of stream requested.\n");
			av_packet_unref(&packet);
			break;
		}

		av_packet_unref(&packet);
	} while (!decode_done);

	if (in_video_st->codec->codec !=NULL) avcodec_close(in_video_st->codec);
	if (num_segments<MAX_SEGMENTS) {
		//make sure all packets are written and then close the last file. 
		avio_flush(oc->pb);
		av_write_trailer(oc);

		for (i = 0; i < oc->nb_streams; i++) {
			av_freep(&oc->streams[i]->codec);
			av_freep(&oc->streams[i]);
		}

		avio_close(oc->pb);
		av_free(oc);
		
		if (num_segments>0){
			actual_segment_durations[num_segments] = (unsigned int) rint(packet_time - segment_start_time);
			if (actual_segment_durations[num_segments] == 0)   actual_segment_durations[num_segments] = 1;
			num_segments++;
			write_index_file(playlistFilename, tempPlaylistName, segmentLength, num_segments,actual_segment_durations, listofs,  baseFileName, baseFileExtension, 1);
		} else { //archive mode
			localtime_r_ex(&end_time);
			fixofn();
		}
	}
// 	struct stat st;
// 	stat(currentOutputFileName, &st);
// 	output_bytes += st.st_size;
	avformat_close_input(&ic);
	break;
}

		

	return 0;
}