Example #1
0
//----------------------------------------------------------------
// main_utf8
// 
int main_utf8(int argc, char **argv)
{
    const char *input = NULL;
    const char *output_prefix = "";
    double target_segment_duration = 0.0;
    char *segment_duration_check = NULL;
    const char *playlist_filename = NULL;
    const char *http_prefix = "";
    long max_tsfiles = 0;
    char *max_tsfiles_check = NULL;
    double prev_segment_time = 0.0;
    double segment_duration = 0.0;
    unsigned int output_index = 0;
    const AVClass *fc = avformat_get_class();
    AVDictionary *format_opts = NULL;
    AVOutputFormat *ofmt = NULL;
    AVFormatContext *ic = NULL;
    AVFormatContext *oc = NULL;
    AVStream *video_st = NULL;
    AVStream *audio_st = NULL;
    AVCodec *codec = NULL;
    char *output_filename = NULL;
    char *pid_filename = NULL;
    int video_index = -1;
    int audio_index = -1;
    int kill_file = 0;
    int decode_done = 0;
    int ret = 0;
    int i = 0;
    TSMStreamLace * streamLace = NULL;
    TSMPlaylist * playlist = NULL;
    const double segment_duration_error_tolerance = 0.05;
    double extra_duration_needed = 0;
    int strict_segment_duration = 0;
    
    av_log_set_level(AV_LOG_INFO);
    
    for (int i = 1; i < argc; i++)
    {
        if (strcmp(argv[i], "-i") == 0)
        {
            if ((argc - i) <= 1) usage(argv, "could not parse -i parameter");
            i++;
            input = argv[i];
        }
        else if (strcmp(argv[i], "-o") == 0)
        {
            if ((argc - i) <= 1) usage(argv, "could not parse -i parameter");
            i++;
            output_prefix = argv[i];
        }
        else if (strcmp(argv[i], "-d") == 0)
        {
            if ((argc - i) <= 1) usage(argv, "could not parse -d parameter");
            i++;
            
            target_segment_duration = strtod(argv[i], &segment_duration_check);
            if (segment_duration_check == argv[i] ||
                target_segment_duration == HUGE_VAL ||
                target_segment_duration == -HUGE_VAL)
            {
                usage3(argv, "invalid segment duration: ", argv[i]);
            }
        }
        else if (strcmp(argv[i], "-x") == 0)
        {
            if ((argc - i) <= 1) usage(argv, "could not parse -x parameter");
            i++;
            playlist_filename = argv[i];
        }
        else if (strcmp(argv[i], "-p") == 0)
        {
            if ((argc - i) <= 1) usage(argv, "could not parse -p parameter");
            i++;
            http_prefix = argv[i];
        }
        else if (strcmp(argv[i], "-w") == 0)
        {
            if ((argc - i) <= 1) usage(argv, "could not parse -w parameter");
            i++;

            max_tsfiles = strtol(argv[i], &max_tsfiles_check, 10);
            if (max_tsfiles_check == argv[i] ||
                max_tsfiles < 0 ||
                max_tsfiles >= INT_MAX)
            {
                usage3(argv, "invalid live stream max window size: ", argv[i]);
            }
        }
        else if (strcmp(argv[i], "-P") == 0)
        {
            if ((argc - i) <= 1) usage(argv, "could not parse -P parameter");
            i++;
            pid_filename = argv[i];
        }
        else if (strcmp(argv[i], "--watch-for-kill-file") == 0)
        {
            // end program when it finds a file with name 'kill':
            kill_file = 1;
        }
        else if (strcmp(argv[i], "--strict-segment-duration") == 0)
        {
            // force segment creation on non-keyframe boundaries:
            strict_segment_duration = 1;
        }
        else if (strcmp(argv[i], "--avformat-option") == 0)
        {
            const AVOption *of;
            const char *opt;
            const char *arg;
            if ((argc - i) <= 1) usage(argv, "could not parse --avformat-option parameter");
            i++;
            opt = argv[i];
            if ((argc - i) <= 1) usage(argv, "could not parse --avformat-option parameter");
            i++;
            arg = argv[i];

            if ((of = av_opt_find(&fc, opt, NULL, 0,
                                  AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)))
                av_dict_set(&format_opts, opt, arg, (of->type == AV_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0);
            else
                usage3(argv, "unknown --avformat-option parameter: ", opt);
        }
        else if (strcmp(argv[i], "--loglevel") == 0)
        {
            const char *arg;
            if ((argc - i) <= 1) usage(argv, "could not parse --loglevel parameter");
            i++;
            arg = argv[i];

            if (loglevel(arg))
                usage3(argv, "unknown --loglevel parameter: ", arg);
        }
    }
    
    if (!input)
    {
        usage(argv, "-i input file parameter must be specified");
    }
    
    if (!playlist_filename)
    {
        usage(argv, "-x m3u8 playlist file parameter must be specified");
    }
    
    if (target_segment_duration == 0.0)
    {
        usage(argv, "-d segment duration parameter must be specified");
    }
    
    // Create PID file
    if (pid_filename)
    {
        FILE* pid_file = fopen_utf8(pid_filename, "wb");
        if (pid_file)
        {
            fprintf(pid_file, "%d", getpid());
            fclose(pid_file);
        }
    }

    av_register_all();
    avformat_network_init();

    if (!strcmp(input, "-")) {
        input = "pipe:";
    }
    
    output_filename = malloc(sizeof(char) * (strlen(output_prefix) + 15));
    if (!output_filename) {
        fprintf(stderr, "Could not allocate space for output filenames\n");
        goto error;
    }

    playlist = createPlaylist(max_tsfiles,
                              target_segment_duration,
                              http_prefix);
    if (!playlist)
    {
        fprintf(stderr, "Could not allocate space for m3u8 playlist structure\n");
        goto error;
    }

    ret = avformat_open_input(&ic, input, NULL, (format_opts) ? &format_opts : NULL);
    if (ret != 0) {
        fprintf(stderr, "Could not open input file, make sure it is an mpegts or mp4 file: %d\n", ret);
        goto error;
    }
    av_dict_free(&format_opts);

    if (avformat_find_stream_info(ic, NULL) < 0) {
        fprintf(stderr, "Could not read stream information\n");
        goto error;
    }

#if LIBAVFORMAT_VERSION_MAJOR > 52 || (LIBAVFORMAT_VERSION_MAJOR == 52 && \
                                       LIBAVFORMAT_VERSION_MINOR >= 45)
    ofmt = av_guess_format("mpegts", NULL, NULL);
#else
    ofmt = guess_format("mpegts", NULL, NULL);
#endif
    
    if (!ofmt) {
        fprintf(stderr, "Could not find MPEG-TS muxer\n");
        goto error;
    }

    oc = avformat_alloc_context();
    if (!oc) {
        fprintf(stderr, "Could not allocated output context\n");
        goto error;
    }
    oc->oformat = ofmt;

    video_index = -1;
    audio_index = -1;

    for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) {
        switch (ic->streams[i]->codec->codec_type) {
            case AVMEDIA_TYPE_VIDEO:
                video_index = i;
                ic->streams[i]->discard = AVDISCARD_NONE;
                video_st = add_output_stream(oc, ic->streams[i]);
                break;
            case AVMEDIA_TYPE_AUDIO:
                audio_index = i;
                ic->streams[i]->discard = AVDISCARD_NONE;
                audio_st = add_output_stream(oc, ic->streams[i]);
                break;
            default:
                ic->streams[i]->discard = AVDISCARD_ALL;
                break;
        }
    }

    av_dump_format(oc, 0, output_prefix, 1);
    
    if (video_index >=0) {
      codec = avcodec_find_decoder(video_st->codec->codec_id);
      if (!codec) {
        fprintf(stderr, "Could not find video decoder, key frames will not be honored\n");
      }

      if (avcodec_open2(video_st->codec, codec, NULL) < 0) {
        fprintf(stderr, "Could not open video decoder, key frames will not be honored\n");
      }
    }

    snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, ++output_index);
    if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) {
        fprintf(stderr, "Could not open '%s'\n", output_filename);
        goto error;
    }

    if (avformat_write_header(oc, NULL)) {
        fprintf(stderr, "Could not write mpegts header to first output file\n");
        goto error;
    }

    prev_segment_time = (double)(ic->start_time) / (double)(AV_TIME_BASE);

    streamLace = createStreamLace(ic->nb_streams);
    
    do {
        double segment_time = 0.0;
        AVPacket packet;
        double packetStartTime = 0.0;
        double packetDuration = 0.0;
        
        if (!decode_done)
        {
            decode_done = av_read_frame(ic, &packet);
            if (!decode_done)
            {
                if (packet.stream_index != video_index &&
                    packet.stream_index != audio_index)
                {
                    av_free_packet(&packet);
                    continue;
                }
                
                double timeStamp = 
                    (double)(packet.pts) * 
                    (double)(ic->streams[packet.stream_index]->time_base.num) /
                    (double)(ic->streams[packet.stream_index]->time_base.den);
                
                if (av_dup_packet(&packet) < 0)
                {
                    fprintf(stderr, "Could not duplicate packet\n");
                    av_free_packet(&packet);
                    break;
                }
                
                insertPacket(streamLace, &packet, timeStamp);
            }
        }
        
        if (countPackets(streamLace) < 50 && !decode_done)
        {
            /* allow the queue to fill up so that the packets can be sorted properly */
            continue;
        }
        
        if (!removePacket(streamLace, &packet))
        {
            if (decode_done)
            {
                /* the queue is empty, we are done */
                break;
            }
            
            assert(decode_done);
            continue;
        }
        
        packetStartTime = 
            (double)(packet.pts) * 
            (double)(ic->streams[packet.stream_index]->time_base.num) /
            (double)(ic->streams[packet.stream_index]->time_base.den);
        
        packetDuration =
            (double)(packet.duration) *
            (double)(ic->streams[packet.stream_index]->time_base.num) /
            (double)(ic->streams[packet.stream_index]->time_base.den);
        
#if !defined(NDEBUG) && (defined(DEBUG) || defined(_DEBUG))
        if (av_log_get_level() >= AV_LOG_VERBOSE)
            fprintf(stderr,
                    "stream %i, packet [%f, %f)\n",
                    packet.stream_index,
                    packetStartTime,
                    packetStartTime + packetDuration);
#endif

        segment_duration = packetStartTime + packetDuration - prev_segment_time;

        // NOTE: segments are supposed to start on a keyframe.
        // If the keyframe interval and segment duration do not match
        // forcing the segment creation for "better seeking behavior"
        // will result in decoding artifacts after seeking or stream switching.
        if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY || strict_segment_duration)) {
            segment_time = packetStartTime;
        }
        else if (video_index < 0) {
            segment_time = packetStartTime;
        }
        else {
            segment_time = prev_segment_time;
        }

        if (segment_time - prev_segment_time + segment_duration_error_tolerance >
            target_segment_duration + extra_duration_needed) 
        {
            avio_flush(oc->pb);
            avio_close(oc->pb);

            // Keep track of accumulated rounding error to account for it in later chunks.
            double segment_duration = segment_time - prev_segment_time;
            int rounded_segment_duration = (int)(segment_duration + 0.5);
            extra_duration_needed += (double)rounded_segment_duration - segment_duration;

            updatePlaylist(playlist,
                           playlist_filename,
                           output_filename,
                           output_index,
                           rounded_segment_duration);
            
            snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, ++output_index);
            if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) {
                fprintf(stderr, "Could not open '%s'\n", output_filename);
                break;
            }

            // close when we find the 'kill' file
            if (kill_file) {
                FILE* fp = fopen("kill", "rb");
                if (fp) {
                    fprintf(stderr, "user abort: found kill file\n");
                    fclose(fp);
                    remove("kill");
                    decode_done = 1;
                    removeAllPackets(streamLace);
                }
            }
            prev_segment_time = segment_time;
        }

        ret = av_interleaved_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_free_packet(&packet);
            break;
        }

        av_free_packet(&packet);
    } while (!decode_done || countPackets(streamLace) > 0);

    av_write_trailer(oc);

    if (video_index >= 0) {
      avcodec_close(video_st->codec);
    }

    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);

    updatePlaylist(playlist,
                   playlist_filename,
                   output_filename,
                   output_index,
                   segment_duration);
    closePlaylist(playlist);
    releasePlaylist(&playlist);
    
    if (pid_filename)
    {
        remove(pid_filename);
    }

    return 0;

error:
    if (pid_filename)
    {
        remove(pid_filename);
    }

    return 1;

}
int main(int argc, char **argv)
{
	if (argc != 5) {
		fprintf(stderr,
			"Usage: %s <segment length> <output location> <filename prefix> <encoding profile>\n",
			argv[0]);
		return 1;
	}

	struct config_info config;

	memset(&config, 0, sizeof(struct config_info));

	config.segment_length = atoi(argv[1]);
	config.temp_directory = argv[2];
	config.filename_prefix = argv[3];
	config.encoding_profile = argv[4];
	config.input_filename = "pipe://1";

	char *output_filename =
	    malloc(sizeof(char) *
		   (strlen(config.temp_directory) + 1 +
		    strlen(config.filename_prefix) + 10));
	if (!output_filename) {
		fprintf(stderr,
			"Segmenter error: Could not allocate space for output filenames\n");
		exit(1);
	}
	// ------------------ Done parsing input --------------

	av_register_all();

	AVInputFormat *input_format = av_find_input_format("mpegts");
	if (!input_format) {
		fprintf(stderr,
			"Segmenter error: Could not find MPEG-TS demuxer\n");
		exit(1);
	}

	AVFormatContext *input_context = NULL;
	int ret = avformat_open_input(&input_context, config.input_filename,
				     input_format, NULL);
	if (ret != 0) {
		fprintf(stderr,
			"Segmenter error: Could not open input file, make sure it is an mpegts file: %d\n",
			ret);
		exit(1);
	}

	if (avformat_find_stream_info(input_context, NULL) < 0) {
		fprintf(stderr,
			"Segmenter error: Could not read stream information\n");
		exit(1);
	}

	AVOutputFormat *output_format = av_guess_format("mpegts", NULL, NULL);
	if (!output_format) {
		fprintf(stderr,
			"Segmenter error: Could not find MPEG-TS muxer\n");
		exit(1);
	}

	AVFormatContext *output_context = avformat_alloc_context();
	if (!output_context) {
		fprintf(stderr,
			"Segmenter error: Could not allocated output context");
		exit(1);
	}
	output_context->oformat = output_format;

	// Don't print warnings when PTS and DTS are identical.
	input_context->flags |= AVFMT_FLAG_IGNDTS;

	int video_index = -1;
	int audio_index = -1;

	AVStream *video_stream;
	AVStream *audio_stream;

	int i;

	for (i = 0;
	     i < input_context->nb_streams && (video_index < 0
					       || audio_index < 0); i++) {
		switch (input_context->streams[i]->codec->codec_type) {
		case AVMEDIA_TYPE_VIDEO:
			video_index = i;
			input_context->streams[i]->discard = AVDISCARD_NONE;
			video_stream =
			    add_output_stream(output_context,
					      input_context->streams[i]);
			break;
		case AVMEDIA_TYPE_AUDIO:
			audio_index = i;
			input_context->streams[i]->discard = AVDISCARD_NONE;
			audio_stream =
			    add_output_stream(output_context,
					      input_context->streams[i]);
			break;
		default:
			input_context->streams[i]->discard = AVDISCARD_ALL;
			break;
		}
	}

#if LIBAVFORMAT_VERSION_MAJOR < 54
	if (av_set_parameters(output_context, NULL) < 0) {
		fprintf(stderr,
			"Segmenter error: Invalid output format parameters\n");
		exit(1);
	}
#endif

	av_dump_format(output_context, 0, config.filename_prefix, 1);

	if (video_index >= 0) {
		AVCodec *codec =
		    avcodec_find_decoder(video_stream->codec->codec_id);
		if (!codec) {
			fprintf(stderr,
				"Segmenter error: Could not find video decoder, key frames will not be honored\n");
		}

		if (avcodec_open2(video_stream->codec, codec, NULL) < 0) {
			fprintf(stderr,
				"Segmenter error: Could not open video decoder, key frames will not be honored\n");
		}
	}

	if (video_stream->codec->ticks_per_frame > 1) {
		// h264 sets the ticks_per_frame and time_base.den but not time_base.num
		// since we don't use ticks_per_frame, adjust time_base.num accordingly.
		video_stream->codec->time_base.num *=
		    video_stream->codec->ticks_per_frame;
	}

	unsigned int output_index = 1;
	snprintf(output_filename,
		 strlen(config.temp_directory) + 1 +
		 strlen(config.filename_prefix) + 10, "%s/%s-%05u.ts",
		 config.temp_directory, config.filename_prefix, output_index++);
	if (avio_open(&output_context->pb, output_filename, AVIO_FLAG_WRITE) < 0) {
		fprintf(stderr, "Segmenter error: Could not open '%s'\n",
			output_filename);
		exit(1);
	}

	if (avformat_write_header(output_context, NULL)) {
		fprintf(stderr,
			"Segmenter error: Could not write mpegts header to first output file\n");
		exit(1);
	}
	// Track initial PTS values so we can subtract them out (removing aduio/video delay, since they seem incorrect).
	int64_t initial_audio_pts = -1;
	int64_t initial_video_pts = -1;

	unsigned int first_segment = 1;
	unsigned int last_segment = 0;

	double prev_segment_time = 0;
	int decode_done;
	do {
		double segment_time;
		AVPacket packet;

		decode_done = av_read_frame(input_context, &packet);
		if (decode_done < 0) {
			break;
		}

		if (av_dup_packet(&packet) < 0) {
			fprintf(stderr,
				"Segmenter error: Could not duplicate packet");
			av_free_packet(&packet);
			break;
		}

		if (packet.stream_index == video_index) {
			if (initial_video_pts < 0)
				initial_video_pts = packet.pts;
			packet.pts -= initial_video_pts;
			packet.dts = packet.pts;
			if (packet.flags & AV_PKT_FLAG_KEY) {
				segment_time =
				    (double)packet.pts *
				    video_stream->time_base.num /
				    video_stream->time_base.den;
			} else {
				segment_time = prev_segment_time;
			}
		} else if (packet.stream_index == audio_index) {
			if (initial_audio_pts < 0)
				initial_audio_pts = packet.pts;
			packet.pts -= initial_audio_pts;
			packet.dts = packet.pts;
			segment_time = prev_segment_time;
		} else {
			segment_time = prev_segment_time;
		}

		// done writing the current file?
		if (segment_time - prev_segment_time >= config.segment_length) {
			avio_flush(output_context->pb);
			avio_close(output_context->pb);

			output_transfer_command(first_segment, ++last_segment,
						0, config.encoding_profile);

			snprintf(output_filename,
				 strlen(config.temp_directory) + 1 +
				 strlen(config.filename_prefix) + 10,
				 "%s/%s-%05u.ts", config.temp_directory,
				 config.filename_prefix, output_index++);
			if (avio_open
			    (&output_context->pb, output_filename,
			     AVIO_FLAG_WRITE) < 0) {
				fprintf(stderr,
					"Segmenter error: Could not open '%s'\n",
					output_filename);
				break;
			}

			prev_segment_time = segment_time;
		}

		ret = av_write_frame(output_context, &packet);

		if (ret < 0) {
			fprintf(stderr,
				"Segmenter error: Could not write frame of stream: %d\n",
				ret);
		} else if (ret > 0) {
			fprintf(stderr,
				"Segmenter info: End of stream requested\n");
			av_free_packet(&packet);
			break;
		}

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

	av_write_trailer(output_context);

	if (video_index >= 0) {
		avcodec_close(video_stream->codec);
	}

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

	avio_close(output_context->pb);
	av_free(output_context);

	output_transfer_command(first_segment, ++last_segment, 1,
				config.encoding_profile);

	return 0;
}
Example #3
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;
}
Example #4
0
int main(int argc, char **argv)
{
  if(argc != 5)
  {
    fprintf(stderr, "Usage: %s <segment length> <output location> <filename prefix> <encoding profile>\n", argv[0]);
    return 1;
  }

  struct config_info config;

  memset(&config, 0, sizeof(struct config_info));

  config.segment_length = atoi(argv[1]); 
  config.temp_directory = argv[2];
  config.filename_prefix = argv[3];
  config.encoding_profile = argv[4];
  config.input_filename = "pipe://1";

  char *output_filename = malloc(sizeof(char) * (strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 10));
  if (!output_filename) 
  {
    fprintf(stderr, "Segmenter error: Could not allocate space for output filenames\n");
    exit(1);
  }

  // ------------------ Done parsing input --------------

  av_register_all();

  AVInputFormat *input_format = av_find_input_format("mpegts");
  if (!input_format) 
  {
    fprintf(stderr, "Segmenter error: Could not find MPEG-TS demuxer\n");
    exit(1);
  }

  AVFormatContext *input_context = NULL;
  int ret = av_open_input_file(&input_context, config.input_filename, input_format, 0, NULL);
  if (ret != 0) 
  {
    fprintf(stderr, "Segmenter error: Could not open input file, make sure it is an mpegts file: %d\n", ret);
    exit(1);
  }

  if (av_find_stream_info(input_context) < 0) 
  {
    fprintf(stderr, "Segmenter error: Could not read stream information\n");
    exit(1);
  }

  AVOutputFormat *output_format = av_guess_format("mpegts", NULL, NULL);
  if (!output_format) 
  {
    fprintf(stderr, "Segmenter error: Could not find MPEG-TS muxer\n");
    exit(1);
  }

  AVFormatContext *output_context = avformat_alloc_context();
  if (!output_context) 
  {
    fprintf(stderr, "Segmenter error: Could not allocated output context");
    exit(1);
  }
  output_context->oformat = output_format;

  int video_index = -1;
  int audio_index = -1;

  AVStream *video_stream;
  AVStream *audio_stream;

  int i;

  for (i = 0; i < input_context->nb_streams && (video_index < 0 || audio_index < 0); i++) 
  {
    switch (input_context->streams[i]->codec->codec_type) {
      case AVMEDIA_TYPE_VIDEO:
        video_index = i;
        input_context->streams[i]->discard = AVDISCARD_NONE;
        video_stream = add_output_stream(output_context, input_context->streams[i]);
        break;
      case AVMEDIA_TYPE_AUDIO:
        audio_index = i;
        input_context->streams[i]->discard = AVDISCARD_NONE;
        audio_stream = add_output_stream(output_context, input_context->streams[i]);
        break;
      default:
        input_context->streams[i]->discard = AVDISCARD_ALL;
        break;
    }
  }

  if (av_set_parameters(output_context, NULL) < 0) 
  {
    fprintf(stderr, "Segmenter error: Invalid output format parameters\n");
    exit(1);
  }

  av_dump_format(output_context, 0, config.filename_prefix, 1);

  if(video_index >= 0)
  {
    AVCodec *codec = avcodec_find_decoder(video_stream->codec->codec_id);
    if (!codec) 
    {
      fprintf(stderr, "Segmenter error: Could not find video decoder, key frames will not be honored\n");
    }

    if (avcodec_open(video_stream->codec, codec) < 0) 
    {
      fprintf(stderr, "Segmenter error: Could not open video decoder, key frames will not be honored\n");
    }
  }

  unsigned int output_index = 1;
  snprintf(output_filename, strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 10, "%s/%s-%05u.ts", config.temp_directory, config.filename_prefix, output_index++);
  if (avio_open(&output_context->pb, output_filename, URL_WRONLY) < 0)
  {
    fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename);
    exit(1);
  }

  if (av_write_header(output_context)) 
  {
    fprintf(stderr, "Segmenter error: Could not write mpegts header to first output file\n");
    exit(1);
  }

  unsigned int first_segment = 1;
  unsigned int last_segment = 0;

  double prev_segment_time = 0;
  int decode_done;
  do 
  {
    double segment_time;
    AVPacket packet;

    decode_done = av_read_frame(input_context, &packet);
    if (decode_done < 0) 
    {
      break;
    }

    if (av_dup_packet(&packet) < 0) 
    {
      fprintf(stderr, "Segmenter error: Could not duplicate packet");
      av_free_packet(&packet);
      break;
    }

    if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY))
    {
      segment_time = (double)video_stream->pts.val * video_stream->time_base.num / video_stream->time_base.den;
    }
    else if (video_index < 0) 
    {
      segment_time = (double)audio_stream->pts.val * audio_stream->time_base.num / audio_stream->time_base.den;
    }
    else 
    {
      segment_time = prev_segment_time;
    }

    // done writing the current file?
    if (segment_time - prev_segment_time >= config.segment_length) 
    {
      avio_flush(output_context->pb);
      avio_close(output_context->pb);

      output_transfer_command(first_segment, ++last_segment, 0, config.encoding_profile);

      snprintf(output_filename, strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 10, "%s/%s-%05u.ts", config.temp_directory, config.filename_prefix, output_index++);
      if (avio_open(&output_context->pb, output_filename, URL_WRONLY) < 0)
      {
        fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename);
        break;
      }

      prev_segment_time = segment_time;
    }

    ret = av_interleaved_write_frame(output_context, &packet);
    if (ret < 0) 
    {
      fprintf(stderr, "Segmenter error: Could not write frame of stream: %d\n", ret);
    }
    else if (ret > 0) 
    {
      fprintf(stderr, "Segmenter info: End of stream requested\n");
      av_free_packet(&packet);
      break;
    }

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

  av_write_trailer(output_context);

  if (video_index >= 0) 
  {
    avcodec_close(video_stream->codec);
  }

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

  avio_close(output_context->pb);
  av_free(output_context);

  output_transfer_command(first_segment, ++last_segment, 1, config.encoding_profile);

  return 0;
}
Example #5
0
int segment(char *input_file, char* base_dirpath, char* output_index_file, char *base_file_name, char* base_file_extension, int segmentLength, int listlen) {
	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;
	int ret;
	int quiet = 0;
	char currentOutputFileName[MAX_FILENAME_LENGTH] = {0};
	double segment_start_time = 0.0;
	char tmp_output_index_file[MAX_FILENAME_LENGTH] = {0};

	unsigned int actual_segment_durations[MAX_SEGMENTS+1];
	double packet_time = 0;

    sprintf(tmp_output_index_file, "%s.tmp", output_index_file);


	av_register_all();
	avformat_network_init(); //just to be safe with later version and be able to handle all kind of input urls
	

	AVStream *in_stream = NULL; 
    AVStream *out_stream = NULL;

	ret = avformat_open_input(&ic, input_file, NULL, NULL);
	if (ret != 0) {
		fprintf(stderr, "Could not open input file %s. Error %d.\n", input_file, ret);
		exit(1);
	}

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

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

	int in_video_index = -1;
	int in_audio_index = -1;
	int out_video_index = -1;
	int out_audio_index = -1;
	int i;
	int listofs = 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");
		avformat_close_input(&ic);
		avformat_free_context(oc);
		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, base_file_name, 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");
	}

	
	snprintf(currentOutputFileName, MAX_FILENAME_LENGTH, "%s/%s-%u%s", base_dirpath, base_file_name, output_index, base_file_extension);
		
	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");
		exit(1);
	}


    unsigned int num_segments = 0;
    int decode_done;
	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;
	
#if USE_H264BSF  
    AVBitStreamFilterContext* h264bsfc =  av_bitstream_filter_init("h264_mp4toannexb");   
#endif	
	double prev_packet_time = 0;
	do {
		AVPacket packet;

		decode_done = av_read_frame(ic, &packet);

		if (decode_done < 0) {
			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) {
#if USE_H264BSF  
            av_bitstream_filter_filter(h264bsfc, ic->streams[in_video_index]->codec, NULL, &packet.data, &packet.size, packet.data, packet.size, 0);  
#endif
			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_free_packet(&packet);
			continue;
		}

		
		if (waitfirstpacket) {
			av_free_packet(&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)) ) { //a keyframe  near or past segmentLength -> SPLIT
			printf("key frame packet time=%f, start time=%f\n", packet_time, segment_start_time);
			
			avio_flush(oc->pb);
			avio_close(oc->pb);
			
			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", base_dirpath, base_file_name, listofs, base_file_extension);
				unlink (currentOutputFileName);
				listofs++; num_segments--;
				memmove(actual_segment_durations,actual_segment_durations+1,num_segments*sizeof(actual_segment_durations[0]));
					
			}
			write_index_file(output_index_file, tmp_output_index_file, segmentLength, num_segments, actual_segment_durations, listofs,  base_file_name, base_file_extension, (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", base_dirpath, base_file_name, output_index, base_file_extension);
			
			
			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;
		}


		in_stream = ic->streams[packet.stream_index];
        out_stream = oc->streams[packet.stream_index]; 
        packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); 
        packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); 
        packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base); 
        packet.pos = -1;

		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_free_packet(&packet);
			break;
		}

		av_free_packet(&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(output_index_file, tmp_output_index_file, segmentLength, num_segments, actual_segment_durations, listofs,  base_file_name, base_file_extension, 1);
		} 
	}

	avformat_close_input(&ic);
	
return 0;

}
Example #6
0
void
create_segments(struct segment_context * ctx) {
 long max_tsfiles = 0;
 char *max_tsfiles_check;
 double prev_segment_time = -1;
 unsigned int output_index = ctx->start_from;

 AVInputFormat *ifmt;
 AVOutputFormat *ofmt;
 AVFormatContext *ic = NULL;
 AVFormatContext *oc;
 AVStream *video_st = NULL;
 AVStream *audio_st = NULL;;
 AVCodec *codec;

 char *output_filename;
 char *output_format;

 int video_index;
 int audio_index;

 unsigned int first_segment = 1;
 unsigned int last_segment = 0;

 int decode_done;
 int ret;
 int i;
 int remove_file;
 int write_index = -1;

 av_register_all();

 ifmt = av_find_input_format("mpegts");
 if (!ifmt) {
   fprintf(stderr, "Could not find MPEG-TS demuxer\n");
   exit(1);
 }

 ret = avformat_open_input(&ic, ctx->input, ifmt, NULL);
 if (ret != 0) {
   fprintf(stderr, "Could not open input file, make sure it is an mpegts file: %d\n", ret);
   exit(1);
 }

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

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

write_index = index_file_open(ctx);

if(write_index >= 0)
  index_file_write_headers(ctx);

oc = avformat_alloc_context();
if (!oc) {
  fprintf(stderr, "Could not allocated output context");
  exit(1);
}
oc->oformat = ofmt;

video_index = -1;
audio_index = -1;

for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) {
 switch (ic->streams[i]->codec->codec_type) {
   case AVMEDIA_TYPE_VIDEO:
   video_index = i;
   ic->streams[i]->discard = AVDISCARD_NONE;
   video_st = add_output_stream(oc, ic->streams[i]);
   break;
   case AVMEDIA_TYPE_AUDIO:
   audio_index = i;
   ic->streams[i]->discard = AVDISCARD_NONE;
   audio_st = add_output_stream(oc, ic->streams[i]);
   break;
   default:
   ic->streams[i]->discard = AVDISCARD_ALL;
   break;
 }
}

av_dump_format(oc, 0, ctx->output_prefix, 1);

if(video_st) {
  codec = avcodec_find_decoder(video_st->codec->codec_id);
  if (!codec) {
    fprintf(stderr, "Could not find video decoder, key frames will not be honored\n");
  }

  if (avcodec_open2(video_st->codec, codec, NULL) < 0) {
   fprintf(stderr, "Could not open video decoder, key frames will not be honored\n");
 }
}

output_filename = malloc(sizeof(char) * (strlen(ctx->output_prefix) + 15));
if (!output_filename) {
 fprintf(stderr, "Could not allocate space for output filename\n");
 exit(1);
}

output_format = malloc(sizeof(char) * (strlen(ctx->output_prefix) + 15));
if (!output_format) {
 fprintf(stderr, "Could not allocate space for output format\n");
 exit(1);
}

sprintf(output_format, "%%s%s%%0%uu.ts", ctx->separator, ctx->precision);

sprintf(output_filename, output_format, ctx->output_prefix, output_index++);

if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) {
  fprintf(stderr, "Could not open '%s'\n", output_filename);
  exit(1);
}

if (avformat_write_header(oc, NULL) < 0) {
 fprintf(stderr, "Could not write mpegts header to first output file\n");
 exit(1);
}

AVPacket packet;

do {

  double segment_time;

  decode_done = av_read_frame(ic, &packet);
  if (decode_done < 0) {
    break;
  }

  if (prev_segment_time < 0) {
    if (packet.stream_index == video_index) {
      prev_segment_time = packet.pts * av_q2d(video_st->time_base);
    } else {
      prev_segment_time = packet.pts * av_q2d(audio_st->time_base);
    }
  }

  if (av_dup_packet(&packet) < 0) {
    fprintf(stderr, "Could not duplicate packet");
    av_free_packet(&packet);
    break;
  }

  if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY)) {
    segment_time = packet.pts * av_q2d(video_st->time_base);
  }
  else if (video_index < 0) {
    segment_time = packet.pts * av_q2d(audio_st->time_base);
  }
  else {
    segment_time = prev_segment_time;
  }

  if (segment_time - prev_segment_time >= ctx->segment_duration) {
    avio_flush(oc->pb);
    avio_close(oc->pb);

    if(write_index >= 0)
      index_file_write_segment(ctx, floor(segment_time - prev_segment_time), output_filename);

    sprintf(output_filename, output_format, ctx->output_prefix, output_index++);

    if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) {
      fprintf(stderr, "Could not open '%s'\n", output_filename);
      break;
    }

    prev_segment_time = segment_time;
  }

  ret = av_write_frame(oc, &packet);

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

  av_free_packet(&packet);
} while (1); /* loop is exited on break */

double input_duration = (double)ic->duration / 1000000;

if(write_index >= 0)
 index_file_write_segment(ctx, ceil(input_duration - prev_segment_time), output_filename);

av_write_trailer(oc);

if(video_st)
avcodec_close(video_st->codec);

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(write_index >= 0)
  index_file_close(ctx);
}
Example #7
0
int main(int argc, char **argv)
{
    double prev_segment_time = 0;
    unsigned int output_index = 1;
    AVInputFormat *ifmt;
    AVOutputFormat *ofmt;
    AVFormatContext *ic = NULL;
    AVFormatContext *oc;
    AVStream *video_st = NULL;
    AVStream *audio_st = NULL;
    AVCodec *codec;
    char *output_filename;
    char *remove_filename;
    int video_index = -1;
    int audio_index = -1;
    unsigned int first_segment = 1;
    unsigned int last_segment = 0;
    int write_index = 1;
    int decode_done;
    char *dot;
    int ret;
    unsigned int i;
    int remove_file;
    struct sigaction act;

    int opt;
    int longindex;
    char *endptr;
    struct options_t options;

    static const char *optstring = "i:d:p:m:u:n:ovh?";

    static const struct option longopts[] = {
        { "input",         required_argument, NULL, 'i' },
        { "duration",      required_argument, NULL, 'd' },
        { "output-prefix", required_argument, NULL, 'p' },
        { "m3u8-file",     required_argument, NULL, 'm' },
        { "url-prefix",    required_argument, NULL, 'u' },
        { "num-segments",  required_argument, NULL, 'n' },
        { "help",          no_argument,       NULL, 'h' },
        { 0, 0, 0, 0 }
    };


    memset(&options, 0 ,sizeof(options));

    /* Set some defaults */
    options.segment_duration = 10;
    options.num_segments = 0;

    do {
        opt = getopt_long(argc, argv, optstring, longopts, &longindex );
        switch (opt) {
            case 'i':
                options.input_file = optarg;
                if (!strcmp(options.input_file, "-")) {
                    options.input_file = "pipe:";
                }
                break;

            case 'd':
                options.segment_duration = strtol(optarg, &endptr, 10);
                if (optarg == endptr || options.segment_duration < 0 || options.segment_duration == -LONG_MAX) {
                    fprintf(stderr, "Segment duration time (%s) invalid\n", optarg);
                    exit(1);
                }
                break;

            case 'p':
                options.output_prefix = optarg;
                break;

            case 'm':
                options.m3u8_file = optarg;
                break;

            case 'u':
                options.url_prefix = optarg;
                break;

            case 'n':
                options.num_segments = strtol(optarg, &endptr, 10);
                if (optarg == endptr || options.num_segments < 0 || options.num_segments >= LONG_MAX) {
                    fprintf(stderr, "Maximum number of ts files (%s) invalid\n", optarg);
                    exit(1);
                }
                break;

            case 'h':
                display_usage();
                break;
        }
    } while (opt != -1);


    /* Check required args where set*/
    if (options.input_file == NULL) {
        fprintf(stderr, "Please specify an input file.\n");
        exit(1);
    }

    if (options.output_prefix == NULL) {
        fprintf(stderr, "Please specify an output prefix.\n");
        exit(1);
    }

    if (options.m3u8_file == NULL) {
        fprintf(stderr, "Please specify an m3u8 output file.\n");
        exit(1);
    }

    if (options.url_prefix == NULL) {
        fprintf(stderr, "Please specify a url prefix.\n");
        exit(1);
    }

    av_register_all();
    remove_filename = malloc(sizeof(char) * (strlen(options.output_prefix) + 15));
    if (!remove_filename) {
        fprintf(stderr, "Could not allocate space for remove filenames\n");
        exit(1);
    }

    output_filename = malloc(sizeof(char) * (strlen(options.output_prefix) + 15));
    if (!output_filename) {
        fprintf(stderr, "Could not allocate space for output filenames\n");
        exit(1);
    }

    options.tmp_m3u8_file = malloc(strlen(options.m3u8_file) + 2);
    if (!options.tmp_m3u8_file) {
        fprintf(stderr, "Could not allocate space for temporary index filename\n");
        exit(1);
    }

    // Use a dotfile as a temporary file
    strncpy(options.tmp_m3u8_file, options.m3u8_file, strlen(options.m3u8_file) + 2);
    dot = strrchr(options.tmp_m3u8_file, '/');
    dot = dot ? dot + 1 : options.tmp_m3u8_file;
    memmove(dot + 1, dot, strlen(dot));
    *dot = '.';

    ifmt = av_find_input_format("mpegts");
    if (!ifmt) {
        fprintf(stderr, "Could not find MPEG-TS demuxer\n");
        exit(1);
    }

    ret = avformat_open_input(&ic, options.input_file, ifmt, NULL);
    if (ret != 0) {
        fprintf(stderr, "Could not open input file, make sure it is an mpegts file: %d\n", ret);
        exit(1);
    }

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

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

    oc = avformat_alloc_context();
    if (!oc) {
        fprintf(stderr, "Could not allocated output context");
        exit(1);
    }
    oc->oformat = ofmt;

    for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) {
        switch (ic->streams[i]->codec->codec_type) {
            case AVMEDIA_TYPE_VIDEO:
                video_index = i;
                ic->streams[i]->discard = AVDISCARD_NONE;
                video_st = add_output_stream(oc, ic->streams[i]);
                break;
            case AVMEDIA_TYPE_AUDIO:
                audio_index = i;
                ic->streams[i]->discard = AVDISCARD_NONE;
                audio_st = add_output_stream(oc, ic->streams[i]);
                break;
            default:
                ic->streams[i]->discard = AVDISCARD_ALL;
                break;
        }
    }

    // Don't print warnings when PTS and DTS are identical.
    ic->flags |= AVFMT_FLAG_IGNDTS;

    av_dump_format(oc, 0, options.output_prefix, 1);

    if (video_st) {
      codec = avcodec_find_decoder(video_st->codec->codec_id);
      if (!codec) {
          fprintf(stderr, "Could not find video decoder %x, key frames will not be honored\n", video_st->codec->codec_id);
      }

      if (avcodec_open2(video_st->codec, codec, NULL) < 0) {
          fprintf(stderr, "Could not open video decoder, key frames will not be honored\n");
      }
    }


    snprintf(output_filename, strlen(options.output_prefix) + 15, "%s-%u.ts", options.output_prefix, output_index++);
    if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) {
        fprintf(stderr, "Could not open '%s'\n", output_filename);
        exit(1);
    }

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

    write_index = !write_index_file(options, first_segment, last_segment, 0);

    /* Setup signals */
    memset(&act, 0, sizeof(act));
    act.sa_handler = &handler;

    sigaction(SIGINT, &act, NULL);
    sigaction(SIGTERM, &act, NULL);

    do {
        double segment_time = prev_segment_time;
        AVPacket packet;

        if (terminate) {
          break;
        }

        decode_done = av_read_frame(ic, &packet);
        if (decode_done < 0) {
            break;
        }

        if (av_dup_packet(&packet) < 0) {
            fprintf(stderr, "Could not duplicate packet");
            av_free_packet(&packet);
            break;
        }

        // Use video stream as time base and split at keyframes. Otherwise use audio stream
        if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY)) {
            segment_time = packet.pts * av_q2d(video_st->time_base);
        }
        else if (video_index < 0) {
            segment_time = packet.pts * av_q2d(audio_st->time_base);
        }
        else {
          segment_time = prev_segment_time;
        }


        if (segment_time - prev_segment_time >= options.segment_duration) {
            av_write_trailer(oc);   // close ts file and free memory
            avio_flush(oc->pb);
            avio_close(oc->pb);

            if (options.num_segments && (int)(last_segment - first_segment) >= options.num_segments - 1) {
                remove_file = 1;
                first_segment++;
            }
            else {
                remove_file = 0;
            }

            if (write_index) {
                write_index = !write_index_file(options, first_segment, ++last_segment, 0);
            }

            if (remove_file) {
                snprintf(remove_filename, strlen(options.output_prefix) + 15, "%s-%u.ts", options.output_prefix, first_segment - 1);
                remove(remove_filename);
            }

            snprintf(output_filename, strlen(options.output_prefix) + 15, "%s-%u.ts", options.output_prefix, output_index++);
            if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) {
                fprintf(stderr, "Could not open '%s'\n", output_filename);
                break;
            }

            // Write a new header at the start of each file
            if (avformat_write_header(oc, NULL)) {
              fprintf(stderr, "Could not write mpegts header to first output file\n");
              exit(1);
            }

            prev_segment_time = segment_time;
        }

        ret = av_interleaved_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_free_packet(&packet);
            break;
        }

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

    av_write_trailer(oc);

    if (video_st) {
      avcodec_close(video_st->codec);
    }

    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 (options.num_segments && (int)(last_segment - first_segment) >= options.num_segments - 1) {
        remove_file = 1;
        first_segment++;
    }
    else {
        remove_file = 0;
    }

    if (write_index) {
        write_index_file(options, first_segment, ++last_segment, 1);
    }

    if (remove_file) {
        snprintf(remove_filename, strlen(options.output_prefix) + 15, "%s-%u.ts", options.output_prefix, first_segment - 1);
        remove(remove_filename);
    }

    return 0;
}
Example #8
0
int main(int argc, char **argv)
{
    const char *input;
    const char *output_prefix;
    double segment_duration;
    char *segment_duration_check;
    const char *index;
    char *tmp_index;
    const char *http_prefix;
    long max_tsfiles = 0;
    char *max_tsfiles_check;
    double prev_segment_time = 0;
    unsigned int output_index = 1;
    AVInputFormat *ifmt;
    AVOutputFormat *ofmt;
    AVFormatContext *ic = NULL;
    AVFormatContext *oc;
    AVStream *video_st;
    AVStream *audio_st;
    AVCodec *codec;
    char *output_filename;
    char *remove_filename;
    int video_index;
    int audio_index;
    unsigned int first_segment = 1;
    unsigned int last_segment = 0;
    int write_index = 1;
    int decode_done;
    char *dot;
    int ret;
    int i;
    int remove_file;

    if (argc < 6 || argc > 7) {
        fprintf(stderr, "Usage: %s <input MPEG-TS file> <segment duration in seconds> <output MPEG-TS file prefix> <output m3u8 index file> <http prefix> [<segment window size>]\n", argv[0]);
        exit(1);
    }

    av_register_all();

    input = argv[1];
    if (!strcmp(input, "-")) {
        input = "pipe:";
    }
    segment_duration = strtod(argv[2], &segment_duration_check);
    if (segment_duration_check == argv[2] || segment_duration == HUGE_VAL || segment_duration == -HUGE_VAL) {
        fprintf(stderr, "Segment duration time (%s) invalid\n", argv[2]);
        exit(1);
    }
    output_prefix = argv[3];
    index = argv[4];
    http_prefix=argv[5];
    if (argc == 7) {
        max_tsfiles = strtol(argv[6], &max_tsfiles_check, 10);
        if (max_tsfiles_check == argv[6] || max_tsfiles < 0 || max_tsfiles >= INT_MAX) {
            fprintf(stderr, "Maximum number of ts files (%s) invalid\n", argv[6]);
            exit(1);
        }
    }

    remove_filename = malloc(sizeof(char) * (strlen(output_prefix) + 15));
    if (!remove_filename) {
        fprintf(stderr, "Could not allocate space for remove filenames\n");
        exit(1);
    }

    output_filename = malloc(sizeof(char) * (strlen(output_prefix) + 15));
    if (!output_filename) {
        fprintf(stderr, "Could not allocate space for output filenames\n");
        exit(1);
    }

    tmp_index = malloc(strlen(index) + 2);
    if (!tmp_index) {
        fprintf(stderr, "Could not allocate space for temporary index filename\n");
        exit(1);
    }

    strncpy(tmp_index, index, strlen(index) + 2);
    dot = strrchr(tmp_index, '/');
    dot = dot ? dot + 1 : tmp_index;
    for (i = strlen(tmp_index) + 1; i > dot - tmp_index; i--) {
        tmp_index[i] = tmp_index[i - 1];
    }
    *dot = '.';

    ifmt = av_find_input_format("mpegts");
    if (!ifmt) {
        fprintf(stderr, "Could not find MPEG-TS demuxer\n");
        exit(1);
    }

    ret = av_open_input_file(&ic, input, ifmt, 0, NULL);
    if (ret != 0) {
        fprintf(stderr, "Could not open input file, make sure it is an mpegts file: %d\n", ret);
        exit(1);
    }

    if (av_find_stream_info(ic) < 0) {
        fprintf(stderr, "Could not read stream information\n");
        exit(1);
    }

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

    oc = avformat_alloc_context();
    if (!oc) {
        fprintf(stderr, "Could not allocated output context");
        exit(1);
    }
    oc->oformat = ofmt;

    video_index = -1;
    audio_index = -1;

    for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) {
        switch (ic->streams[i]->codec->codec_type) {
            case AVMEDIA_TYPE_VIDEO:
                video_index = i;
                ic->streams[i]->discard = AVDISCARD_NONE;
                video_st = add_output_stream(oc, ic->streams[i]);
                break;
            case AVMEDIA_TYPE_AUDIO:
                audio_index = i;
                ic->streams[i]->discard = AVDISCARD_NONE;
                audio_st = add_output_stream(oc, ic->streams[i]);
                break;
            default:
                ic->streams[i]->discard = AVDISCARD_ALL;
                break;
        }
    }

    if (av_set_parameters(oc, NULL) < 0) {
        fprintf(stderr, "Invalid output format parameters\n");
        exit(1);
    }

    dump_format(oc, 0, output_prefix, 1);

    codec = avcodec_find_decoder(video_st->codec->codec_id);
    if (!codec) {
        fprintf(stderr, "Could not find video decoder, key frames will not be honored\n");
    }

    if (avcodec_open(video_st->codec, codec) < 0) {
        fprintf(stderr, "Could not open video decoder, key frames will not be honored\n");
    }

    snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, output_index++);
    if (url_fopen(&oc->pb, output_filename, URL_WRONLY) < 0) {
        fprintf(stderr, "Could not open '%s'\n", output_filename);
        exit(1);
    }

    if (av_write_header(oc)) {
        fprintf(stderr, "Could not write mpegts header to first output file\n");
        exit(1);
    }

    write_index = !write_index_file(index, tmp_index, segment_duration, output_prefix, http_prefix, first_segment, last_segment, 0, max_tsfiles);

    do {
        double segment_time;
        AVPacket packet;

        decode_done = av_read_frame(ic, &packet);
        if (decode_done < 0) {
            break;
        }

        if (av_dup_packet(&packet) < 0) {
            fprintf(stderr, "Could not duplicate packet");
            av_free_packet(&packet);
            break;
        }

        if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY)) {
            segment_time = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den;
        }
        else if (video_index < 0) {
            segment_time = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;
        }
        else {
            segment_time = prev_segment_time;
        }

        if (segment_time - prev_segment_time >= segment_duration) {
            put_flush_packet(oc->pb);
            url_fclose(oc->pb);

            if (max_tsfiles && (int)(last_segment - first_segment) >= max_tsfiles - 1) {
                remove_file = 1;
                first_segment++;
            }
            else {
                remove_file = 0;
            }

            if (write_index) {
                write_index = !write_index_file(index, tmp_index, segment_duration, output_prefix, http_prefix, first_segment, ++last_segment, 0, max_tsfiles);
            }

            if (remove_file) {
                snprintf(remove_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, first_segment - 1);
                remove(remove_filename);
            }

            snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, output_index++);
            if (url_fopen(&oc->pb, output_filename, URL_WRONLY) < 0) {
                fprintf(stderr, "Could not open '%s'\n", output_filename);
                break;
            }

            prev_segment_time = segment_time;
        }

        ret = av_interleaved_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_free_packet(&packet);
            break;
        }

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

    av_write_trailer(oc);

    avcodec_close(video_st->codec);

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

    url_fclose(oc->pb);
    av_free(oc);

    if (max_tsfiles && (int)(last_segment - first_segment) >= max_tsfiles - 1) {
        remove_file = 1;
        first_segment++;
    }
    else {
        remove_file = 0;
    }

    if (write_index) {
        write_index_file(index, tmp_index, segment_duration, output_prefix, http_prefix, first_segment, ++last_segment, 1, max_tsfiles);
    }

    if (remove_file) {
        snprintf(remove_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, first_segment - 1);
        remove(remove_filename);
    }

    return 0;
}
Example #9
0
static VALUE segmenter_segment(VALUE klass, VALUE input_, VALUE output_prefix_, VALUE duration_ ) {

    const char *input;
    const char *output_prefix;
    int segment_duration;
    long max_tsfiles = 0;
    double prev_segment_time = 0;
    unsigned int output_index = 1;
    AVInputFormat *ifmt;
    AVOutputFormat *ofmt;
    AVFormatContext *ic = NULL;
    AVFormatContext *oc;
    AVStream *video_st;
    AVStream *audio_st;
    AVCodec *codec;
    char *output_filename;
    char *remove_filename;
    int video_index;
    int audio_index;
    unsigned int first_segment = 1;
    unsigned int last_segment = 0;
    int decode_done;
    int ret;
    unsigned int i;
    int remove_file;
    
	bool soundOnly = false;

    VALUE sArray = rb_ary_new();
    av_register_all();
    av_log_set_level(AV_LOG_PANIC);

    input = RSTRING_PTR(input_);
    output_prefix = RSTRING_PTR(output_prefix_);
    segment_duration = (FIX2INT(duration_));
	
    char *folder = dirname2(strdup(input));
    
    remove_filename = malloc(sizeof(char) * (strlen(output_prefix) + 15));
    if (!remove_filename) {
        rb_raise(rb_eNoMemError, "Could not allocate space for remove filenames");
    }
    
    output_filename = malloc(sizeof(char) * (strlen(output_prefix) + strlen(folder) + 15));
    if (!output_filename) {
        rb_raise(rb_eNoMemError, "Could not allocate space for output filenames");
    }
    
        
    ifmt = av_find_input_format("mpegts");
    if (!ifmt) {
        rb_raise(rb_eException, "Could not find MPEG-TS demuxer");
    }
    
    ret = av_open_input_file(&ic, input, ifmt, 0, NULL);
    if (ret != 0) {
        rb_raise(rb_eException, "Could not open input file, make sure it is an mpegts file: %d %s", ret, input);
    }
    
    if (av_find_stream_info(ic) < 0) {
        rb_raise(rb_eException, "Could not read stream information");
    }
    
    ofmt = av_guess_format("mpegts", NULL, NULL);
    if (!ofmt) {
        rb_raise(rb_eException, "Could not find MPEG-TS muxer");
    }
    
    oc = avformat_alloc_context();
    if (!oc) {
        rb_raise(rb_eException, "Could not allocated output context");
    }
    oc->oformat = ofmt;

    ic->flags |= AVFMT_FLAG_IGNDTS;
    
    video_index = -1;
    audio_index = -1;
    
    for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) {
        switch (ic->streams[i]->codec->codec_type) {
            case CODEC_TYPE_VIDEO:
                video_index = i;
                ic->streams[i]->discard = AVDISCARD_NONE;
                video_st = add_output_stream(oc, ic->streams[i]);
                break;
            case CODEC_TYPE_AUDIO:
                audio_index = i;
                ic->streams[i]->discard = AVDISCARD_NONE;
                audio_st = add_output_stream(oc, ic->streams[i]);
                break;
            default:
                ic->streams[i]->discard = AVDISCARD_ALL;
                break;
        }
    }

	if(!soundOnly) {
		soundOnly = (video_st != NULL);
	}

    if (av_set_parameters(oc, NULL) < 0) {
        rb_raise(rb_eException, "Invalid output format parameters");
    }
    
    dump_format(oc, 0, output_prefix, 1);



	if (!soundOnly) {
		if(video_st == NULL) {
			fprintf(stderr, "video_st is fail\n");
			rb_raise(rb_eException, "video_st fail");
			exit(1);
		}

		if(video_st->codec == NULL) {
			fprintf(stderr,"codec is fail\n");
			rb_raise(rb_eException, "codec fail");
			exit(1);
		}

		if(video_st->codec->codec_id == NULL) {
			fprintf(stderr, "codec_id is fail\n");
			rb_raise(rb_eException, "codec fail");
			exit(1);
		}

		codec = avcodec_find_decoder(video_st->codec->codec_id);
	    if (!codec) {
	        rb_raise(rb_eException, "Could not find video decoder, key frames will not be honored");
	    }
		
	    if (avcodec_open(video_st->codec, codec) < 0) {
	        rb_raise(rb_eException, "Could not open video decoder, key frames will not be honored");
	    }
    
    
	    if (video_st->codec->ticks_per_frame > 1) {
	        // h264 sets the ticks_per_frame and time_base.den but not time_base.num
	        // since we don't use ticks_per_frame, adjust time_base.num accordingly.
	        video_st->codec->time_base.num *= video_st->codec->ticks_per_frame;
	    }
	}
    
    snprintf(output_filename, strlen(output_prefix) + strlen(folder) + 15, "%s/%s-%u.ts", folder, output_prefix, output_index++);
    if (url_fopen(&oc->pb, output_filename, URL_WRONLY) < 0) {
        rb_raise(rb_eException, "Could not open '%s'", output_filename);
    }
    
    if (av_write_header(oc)) {
        rb_raise(rb_eException, "Could not write mpegts header to first output file");
    }
    
    //write_index = !write_index_file(index, tmp_index, segment_duration, output_prefix, http_prefix, first_segment, last_segment, 0, max_tsfiles);
    int64_t initial_audio_pts = -1;
    int64_t initial_video_pts = -1;
	double segment_time;
    do {
		
        AVPacket packet;
        //av_init_packet(&packet);
        decode_done = av_read_frame(ic, &packet);
        if (decode_done < 0) {
            break;
        }
        
        if (av_dup_packet(&packet) < 0) {
            rb_raise(rb_eException, "Could not duplicate packet");
            av_free_packet(&packet);
            break;
        }
		
		if (!soundOnly) {
	        if (packet.stream_index == video_index) {
	            if (initial_video_pts < 0) 
					initial_video_pts = packet.pts;
					
	            packet.pts -= initial_video_pts;
	            packet.dts = packet.pts;
	            if (packet.flags & AV_PKT_FLAG_KEY) {
	                segment_time = (double)packet.pts * video_st->time_base.num / video_st->time_base.den;
	            } else {
	                segment_time = prev_segment_time;            }
	        } else if (packet.stream_index == audio_index) {
	            if (initial_audio_pts < 0) initial_audio_pts = packet.pts;
	            packet.pts -= initial_audio_pts;
	            packet.dts = packet.pts;
	            segment_time = prev_segment_time;
	        } else {
	            segment_time = prev_segment_time;
	            segment_time = prev_segment_time;
	        }			
		} else {

			if (packet.stream_index == audio_index) {
				
	            if (initial_audio_pts < 0) 
					initial_audio_pts = packet.pts;
				
				if (packet.flags & AV_PKT_FLAG_KEY) {
					segment_time = (double)packet.pts * audio_st->time_base.num / audio_st->time_base.den;
				} else {
	            	segment_time = prev_segment_time;	
				}
					
	            packet.pts -= initial_audio_pts;
	            packet.dts = packet.pts;

	        } else {
	            segment_time = prev_segment_time;
	            segment_time = prev_segment_time;
	        }
		
		}



        if (segment_time - prev_segment_time >= segment_duration) {
            put_flush_packet(oc->pb);
            url_fclose(oc->pb);
            
            if (max_tsfiles && (int)(last_segment - first_segment) >= max_tsfiles - 1) {
                remove_file = 1;
                first_segment++;
            }
            else {
                remove_file = 0;
            }
            
            
            // Create Segment object
            VALUE seg = rb_obj_alloc(rb_cAvSegment);            

            rb_obj_call_init(seg, 0, 0);
            rb_iv_set(seg, "@index", INT2FIX(++last_segment));
            rb_iv_set(seg, "@duration",INT2FIX((int)floor((segment_time - prev_segment_time))));
            rb_iv_set(seg, "@filename", rb_str_new2(output_filename));
            
            rb_ary_push(sArray, seg);
            
            if (remove_file) {
                snprintf(remove_filename, strlen(output_prefix) + strlen(folder) + 15, "%s/%s-%u.ts", folder, output_prefix, first_segment - 1);
                //snprintf(remove_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, first_segment - 1);
                remove(remove_filename);
            }
            
//            snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, output_index++);
            snprintf(output_filename, strlen(output_prefix) + strlen(folder) + 15, "%s/%s-%u.ts", folder, output_prefix, output_index++);
            if (url_fopen(&oc->pb, output_filename, URL_WRONLY) < 0) {
                fprintf(stderr, "Could not open '%s'\n", output_filename);
                break;
            }
            
            prev_segment_time = segment_time;
        }

        ret = av_interleaved_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_free_packet(&packet);
            break;
        }
        
        av_free_packet(&packet);
    } while (!decode_done);

    av_write_trailer(oc);

	if (!soundOnly)
    	avcodec_close(video_st->codec);

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

		if (&oc->streams[i] != NULL)
        	av_freep(&oc->streams[i]);
    }

    url_fclose(oc->pb);
    av_free(oc);
    
    if (max_tsfiles && (int)(last_segment - first_segment) >= max_tsfiles - 1) {
        remove_file = 1;
        first_segment++;
    }
    else {
        remove_file = 0;
    }
 
    if (remove_file) {
        snprintf(remove_filename, strlen(output_prefix) + strlen(folder) + 15, "%s/%s-%u.ts", folder, output_prefix, first_segment - 1);
        remove(remove_filename);
    }
    return sArray;
}
Example #10
0
void open_context(AVFormatContext **ic, const char *input_file, const char *key, AVInputFormat *ifmt, AVOutputFormat **ofmt, AVFormatContext **oc, AVStream **video_st, AVStream **audio_st, int *video_index, int *audio_index){
    int ret;
    int i;
    AVCodec *codec;

    ret = avformat_open_input(ic, input_file, ifmt, NULL);
    if (ret != 0) {
        fprintf(stderr, "Could not open input file, make sure it is an mpegts file: %d\n", ret);
        exit(1);
    }

    if (avformat_find_stream_info(*ic, NULL) < 0) {
        fprintf(stderr, "Could not read stream information\n");
        exit(1);
    }

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

    *oc = avformat_alloc_context();

    if (!*oc) {
        fprintf(stderr, "Could not allocated output context");
        exit(1);
    }
    (*oc)->oformat = *ofmt;

    for (i = 0; i < (*ic)->nb_streams && (*video_index < 0 || *audio_index < 0); i++) {
        switch ((*ic)->streams[i]->codec->codec_type) {
            case AVMEDIA_TYPE_VIDEO:
                *video_index = i;
                (*ic)->streams[i]->discard = AVDISCARD_NONE;
                *video_st = add_output_stream(*oc, (*ic)->streams[i]);
                break;
            case AVMEDIA_TYPE_AUDIO:
                *audio_index = i;
                (*ic)->streams[i]->discard = AVDISCARD_NONE;
                *audio_st = add_output_stream(*oc, (*ic)->streams[i]);
                break;
            default:
                (*ic)->streams[i]->discard = AVDISCARD_ALL;
                break;
        }
    }

    // Don't print warnings when PTS and DTS are identical.
    (*ic)->flags |= AVFMT_FLAG_IGNDTS;

    av_dump_format(*oc, 0, key, 1);

    if (*video_st) {
      codec = avcodec_find_decoder((*video_st)->codec->codec_id);
      if (!codec) {
          fprintf(stderr, "Could not find video decoder %x, key frames will not be honored\n", (*video_st)->codec->codec_id);
      }

      if (avcodec_open2((*video_st)->codec, codec, NULL) < 0) {
          fprintf(stderr, "Could not open video decoder, key frames will not be honored\n");
      }
    }

}
Example #11
0
int segment_process(struct config_info config)

{
  unsigned int output_filename_size = sizeof(char) * (strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 100);
  char *output_filename = malloc(output_filename_size);
 
  if (!output_filename) 
  {
    fprintf(stderr, "Segmenter error: Could not allocate space for output filenames\n");
    exit(1);
  }

   
  // we try to approximate the time of first received frame
  // by taking system timestamp and storing first frame timestamp
  time_t sys_time; time(&sys_time);
  double  on_start_timestamp = (double)sys_time;

  av_register_all();

  AVInputFormat *input_format = av_find_input_format("mpegts");
  if (!input_format) 
  {
    fprintf(stderr, "Segmenter error: Could not find MPEG-TS demuxer\n");
    exit(1);
  }

  AVFormatContext *input_context = NULL;
  int ret;
  ret  = avformat_open_input(&input_context, config.input_filename, input_format,  NULL);
  if (ret != 0) 
  {
	print_av_error("Could not open input file, make sure it is an mpegts", ret);
    exit(1);
  }

  ret = avformat_find_stream_info(input_context, NULL);
  if (ret < 0) 
  {
	print_av_error("Could not read stream information", ret);
    exit(1);
  }

  fprintf(stderr, "segmenter-debug: start time %lld %lld \n", input_context->start_time, input_context->timestamp);

  AVOutputFormat *output_format = av_guess_format("mpegts", NULL, NULL);
  if (!output_format) 
  {
    fprintf(stderr, "Segmenter error: Could not find MPEG-TS muxer\n");
    exit(1);
  }

  AVFormatContext *output_context = avformat_alloc_context();
  if (!output_context) 
  {
    fprintf(stderr, "Segmenter error: Could not allocated output context");
    exit(1);
  }
  output_context->oformat = output_format;

  int video_index = -1;
  int audio_index = -1;

  AVStream *video_stream;
  AVStream *audio_stream;

  int i;
  int index_map[20];
  memset (index_map, -1, sizeof(int)*20);

  for (i = 0; i < input_context->nb_streams && (video_index < 0 || audio_index < 0); i++) 
  {
    switch (input_context->streams[i]->codec->codec_type) {
      case AVMEDIA_TYPE_VIDEO:
        video_index = i;
        input_context->streams[i]->discard = AVDISCARD_NONE;
        video_stream = add_output_stream(output_context, input_context->streams[i]);
	index_map[i] = video_stream->index;
        break;
      case AVMEDIA_TYPE_AUDIO:
        audio_index = i;
        input_context->streams[i]->discard = AVDISCARD_NONE;
        audio_stream = add_output_stream(output_context, input_context->streams[i]);
	index_map[i] = audio_stream->index;
        break;
      default:
        input_context->streams[i]->discard = AVDISCARD_ALL;
        fprintf(stderr, "segmenter-warning: stream index %d from source woudl be skipped \n", i);
        break;
    }
  }
#if LIBAVFORMAT_VERSION_MAJOR < 54
  if (av_set_parameters(output_context, NULL) < 0) 
  {
    fprintf(stderr, "Segmenter error: Invalid output format parameters\n");
    exit(1);
  }
#endif

  av_dump_format(output_context, 0, config.filename_prefix, 1);

  if(video_index >= 0)
  {
    AVCodec *codec = avcodec_find_decoder(video_stream->codec->codec_id);
    if (!codec) 
    {
      fprintf(stderr, "Segmenter error: Could not find video decoder, key frames will not be honored\n");
    }

    if (avcodec_open2(video_stream->codec, codec, NULL) < 0) 
    {
      fprintf(stderr, "Segmenter error: Could not open video decoder, key frames will not be honored\n");
    }
  }

  unsigned int output_index = 1;
  snprintf(output_filename, output_filename_size, "%s/%s-%u-%010u.ts", config.temp_directory, config.filename_prefix, config.run_cycle, output_index++);
  if (avio_open(&output_context->pb, output_filename, AVIO_FLAG_WRITE) < 0) 
  {
    fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename);
    exit(1);
  }

  if (avformat_write_header(output_context, NULL)) 
  {
    fprintf(stderr, "Segmenter error: Could not write mpegts header to first output file\n");
    exit(1);
  }

  unsigned int first_segment = 1;
  unsigned int last_segment = 0;
  
  double prev_segment_time = 0;
  double first_segment_time = -1.0;
  int decode_done;
  double segment_time = 0;
  
  unsigned int pktWriteFrameErrorCount = 0;
  do 
  {
    AVPacket packet;

    decode_done = av_read_frame(input_context, &packet);
    if (decode_done < 0) 
    {
      break;
    }

    if ((ret = av_dup_packet(&packet)) < 0) 
    {
      print_av_error("Could not duplicate packet", ret);
      av_free_packet(&packet);
      break;
    }

    if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY)) 
    {
      segment_time = (double)video_stream->pts.val * video_stream->time_base.num / video_stream->time_base.den;
      if (first_segment_time <= 0) 
         fprintf(stderr, "segmenter-debug: received new time from video I frame : %lf\n", segment_time);
    }
    else if (video_index < 0) 
    {
      segment_time = (double)audio_stream->pts.val * audio_stream->time_base.num / audio_stream->time_base.den;
      if (first_segment_time <= 0)
         fprintf(stderr, "segmenter-debug: received new time from audio PTS : %lf\n", segment_time);
    }
    else 
    {
      segment_time = prev_segment_time;
    }

    // initialy previous segment time would be zero, avoid receiving huge difference
    if (prev_segment_time == 0 && segment_time > 0) {
        prev_segment_time = segment_time;
    }

    if (first_segment_time < 0 && segment_time > 0) {
	first_segment_time = segment_time; // this is relative time in MS
    }
    
    //fprintf(stderr, "segmenter-debug: videoPTS=%lf audioPTS=%lf\n", (double)video_stream->pts.val * video_stream->time_base.num / video_stream->time_base.den, (double)audio_stream->pts.val * audio_stream->time_base.num / audio_stream->time_base.den); 
    //fprintf(stderr, "segmenter-debug: cur=%.02lf prev=%.02lf onstartTS=%.02lf first=%.02lf\n", segment_time, prev_segment_time, on_start_timestamp, first_segment_time);

    // timestamps in the streams received from IRDs are relative, 
    // if there's a mismatch - time to restart segmentation process, as entire TS may change
    
    // done writing the current file?
    if (segment_time - prev_segment_time >= config.segment_length) 
    {
      avio_flush(output_context->pb);
      avio_close(output_context->pb);

      output_transfer_command(++last_segment, (segment_time-first_segment_time+on_start_timestamp), (segment_time-prev_segment_time), 0, output_filename);

      snprintf(output_filename, output_filename_size, "%s/%s-%u-%010u.ts", config.temp_directory, config.filename_prefix, config.run_cycle,output_index++);
      if (avio_open(&output_context->pb, output_filename, AVIO_FLAG_WRITE) < 0) 
      {
        fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename);
        break;
      }

      prev_segment_time = segment_time;
    }
    
    
    // because indicies from original and destination packets differ, perform correction
    if (index_map[packet.stream_index] < 0) {
	  fprintf(stderr, "segmenter-debug: skipping packet pos=%lld size=%d stream=%d flags=%d pts=%lld\n", packet.pos, packet.size, packet.stream_index, packet.flags, packet.pts); 
      ret = -1000;
    }else if (packet.size > 0) {
  	    packet.stream_index = index_map[packet.stream_index];
    	ret = av_interleaved_write_frame(output_context, &packet);
        // fprintf(stderr, "segmenter-error: [%d] handling packet pos=%lld size=%d stream=%d flags=%d pts=%lld\n", ret, packet.pos, packet.size, packet.stream_index, packet.flags, packet.pts);
	}else{
		fprintf(stderr, "segmenter-debug: empty packet\n");
		ret = -1001;
    }
    av_free_packet(&packet);
    
    if (ret < 0) 
    {
      // fprintf(stderr, "segmenter-error: handling packet pos=%lld size=%d stream=%d flags=%d pts=%lld\n", packet.pos, packet.size, packet.stream_index, packet.flags, packet.pts);
      // print_av_error("av_interleaved_write_frame ",ret);
      pktWriteFrameErrorCount ++;
      if (first_segment_time > 0 && pktWriteFrameErrorCount > PKT_WRITE_FRAME_ERROR_LIMIT) {
          fprintf(stderr, "segmenter-error: can't handle last %u packets. requesting process restart.\n", pktWriteFrameErrorCount);
          break;
      }
    }
    else if (ret > 0) 
    {
      fprintf(stderr, "Segmenter info: End of stream requested\n");
      av_free_packet(&packet);
      break;
    }else{
      pktWriteFrameErrorCount = 0; // clear av_interleaved_write_frame() error count
    }
  } while (!decode_done);

  av_write_trailer(output_context);

  if (video_index >= 0) 
  {
    avcodec_close(video_stream->codec);
  }

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

  avio_close(output_context->pb);
  av_free(output_context);
  av_close_input_file(input_context);

      output_transfer_command(++last_segment, (segment_time-first_segment_time+on_start_timestamp), (segment_time-prev_segment_time), 1, output_filename);
  return 0;
}
Example #12
-2
//----------------------------------------------------------------
// main_utf8
// 
int main_utf8(int argc, char **argv)
{
	const char *input = NULL;
	const char *output_prefix = "";
	double target_segment_duration = 0.0;
	char *segment_duration_check = NULL;
	const char *playlist_filename = NULL;
	const char *http_prefix = "";
	long max_tsfiles = 0;
	char *max_tsfiles_check = NULL;
	double prev_segment_time = 0.0;
	double segment_duration = 0.0;
	unsigned int output_index = 1;
	const AVClass *fc = avformat_get_class();
	AVDictionary *format_opts = NULL;
	AVOutputFormat *ofmt = NULL;
	AVFormatContext *ic = NULL;
	AVFormatContext *oc = NULL;
	AVStream *video_st = NULL;
	AVStream *audio_st = NULL;
	AVCodec *codec = NULL;
	char *output_filename = NULL; 	
	int if_save_keyframe = 0;			//add by wanggm
	char *keyframeinfo_filename = NULL;	//add by wanggm
	json_object *obj = NULL;			//add by wanggm
	json_object *info_arr_obj = NULL;	//add by wanggm

	int if_monitor_related_process = 0;	//add by wanggm
	pid_t relatedProcessPid = 1; 		//add by wanggm
	char *pid_filename = NULL;
	int video_index = -1;
	int audio_index = -1;
	int kill_file = 0;
	int decode_done = 0;
	int ret = 0;
	int i = 0;
	TSMStreamLace * streamLace = NULL;
	TSMPlaylist * playlist = NULL;
	const double segment_duration_error_tolerance = 0.05;
	double extra_duration_needed = 0;
	int strict_segment_duration = 0;

	av_log_set_level(AV_LOG_INFO);


	for (i = 1; i < argc; i++)
	{
		if (strcmp(argv[i], "-i") == 0)
		{
			if ((argc - i) <= 1)
				usage(argv, "could not parse -i parameter");
			i++;
			input = argv[i];
		}
		else if (strcmp(argv[i], "-o") == 0)
		{
			if ((argc - i) <= 1)
				usage(argv, "could not parse -o parameter");
			i++;
			output_prefix = argv[i];
		}
		else if (strcmp(argv[i], "-d") == 0)
		{
			if ((argc - i) <= 1)
				usage(argv, "could not parse -d parameter");
			i++;

			target_segment_duration = strtod(argv[i], &segment_duration_check);
			if (segment_duration_check
					== argv[i] || target_segment_duration == HUGE_VAL
					|| target_segment_duration == -HUGE_VAL){
				usage3(argv, "invalid segment duration: ", argv[i]);
			}
		}
		else if (strcmp(argv[i], "-x") == 0)
		{
			if ((argc - i) <= 1)
				usage(argv, "could not parse -x parameter");
			i++;
			playlist_filename = argv[i];
		}
		else if (strcmp(argv[i], "-p") == 0)
		{
			if ((argc - i) <= 1)
				usage(argv, "could not parse -p parameter");
			i++;
			http_prefix = argv[i];
		}
		else if (strcmp(argv[i], "-w") == 0)
		{
			if ((argc - i) <= 1)
				usage(argv, "could not parse -w parameter");
			i++;

			max_tsfiles = strtol(argv[i], &max_tsfiles_check, 10);
			if (max_tsfiles_check == argv[i] || max_tsfiles < 0
					|| max_tsfiles >= INT_MAX)
			{
				usage3(argv, "invalid live stream max window size: ", argv[i]);
			}
		}
		else if (strcmp(argv[i], "-P") == 0)
		{
			if ((argc - i) <= 1)
				usage(argv, "could not parse -P parameter");
			i++;
			pid_filename = argv[i];
		}
		else if (strcmp(argv[i], "--watch-for-kill-file") == 0)
		{
			// end program when it finds a file with name 'kill':
			kill_file = 1;
		}
		else if (strcmp(argv[i], "--strict-segment-duration") == 0)
		{
			// force segment creation on non-keyframe boundaries:
			strict_segment_duration = 1;
		}
		else if (strcmp(argv[i], "--avformat-option") == 0)
		{
			const AVOption *of;
			const char *opt;
			const char *arg;
			if ((argc - i) <= 1)
				usage(argv, "could not parse --avformat-option parameter");
			i++;
			opt = argv[i];
			if ((argc - i) <= 1)
				usage(argv, "could not parse --avformat-option parameter");
			i++;
			arg = argv[i];

			if ((of = av_opt_find(&fc, opt, NULL, 0,
					AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)))
				av_dict_set(&format_opts, opt, arg,
						(of->type == AV_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0);
			else
				usage3(argv, "unknown --avformat-option parameter: ", opt);
		}
		else if (strcmp(argv[i], "--loglevel") == 0)
		{
			const char *arg;
			if ((argc - i) <= 1)
				usage(argv, "could not parse --loglevel parameter");
			i++;
			arg = argv[i];

			if (loglevel(arg))
				usage3(argv, "unknown --loglevel parameter: ", arg);
		}
		else if (strcmp(argv[i], "-k") == 0)
		{ //add by wanggm for save key frame information into json file.
			if ((argc - i) <= 1)
				usage(argv, "could not parse -k parameter");
			i++;
			if_save_keyframe = atoi(argv[i]);
		}
		else if( strcmp(argv[i], "-s") == 0)
		{//add by wanggm for set the start index of ts file.
			if ( (argc -i ) <= 1)
				usage(argv, "could not parse -s parmeter");
			i++;
			
			char *output_index_check = NULL;
			output_index  = strtol(argv[i], &output_index_check, 10);
			if ( output_index_check== argv[i] || output_index < 0
					|| output_index >= INT_MAX)
			{
				usage3(argv, "invalid start index of ts file: ", argv[i]);
			}
			
		}
		else if( strcmp(argv[i], "-m") == 0)
		{ // add by wanggm for exit by monitor the process of which pid is given. 
			if ((argc - i) <= 1)
				usage(argv, "could not parse -m parmeter");
			i++;

			if_monitor_related_process = 1;
			unsigned int tmpPid= atoi(argv[i]);
			if( tmpPid > 0)
			{  
				relatedProcessPid = (pid_t) tmpPid;
				fprintf(stdout, "%s I will exit when the process PID= %d exit.\n", getSystemTime(timeChar), relatedProcessPid);
			}
		}
	}

	
	if (!input)
	{
		usage(argv, "-i input file parameter must be specified");
	}

	if (!playlist_filename)
	{
		usage(argv, "-x m3u8 playlist file parameter must be specified");
	}

	if (target_segment_duration == 0.0)
	{
		usage(argv, "-d segment duration parameter must be specified");
	}

	if( output_index <= 0 )
	{
		output_index = 1;	
	}

	if( 1 == if_monitor_related_process)
	{
		pthread_t id;
		pthread_create(&id, NULL, (void*)monitor_process, relatedProcessPid);
	}


	// Create PID file
	if (pid_filename)
	{
		FILE* pid_file = fopen_utf8(pid_filename, "wb");
		if (pid_file)
		{
			fprintf(pid_file, "%d", getpid());
			fclose(pid_file);
		}
	}


	av_register_all();
	avformat_network_init();

	if (!strcmp(input, "-"))
	{
		input = "pipe:";
	}

	output_filename = (char*) malloc(
			sizeof(char) * (strlen(output_prefix) + 15));
	//add by wanggm
	if(  if_save_keyframe == 1)
	{ 
		keyframeinfo_filename = (char*) malloc(
			sizeof(char)* (strlen(output_prefix) + 15));
	}
	if (!output_filename || (1 == if_save_keyframe && !keyframeinfo_filename))
	{
		fprintf(stderr, "%s Could not allocate space for output filenames\n", getSystemTime( timeChar));
		goto error;
	}

	playlist = createPlaylist(max_tsfiles, target_segment_duration,
			http_prefix);
	if (!playlist)
	{
		fprintf(stderr,
				"%s Could not allocate space for m3u8 playlist structure\n", getSystemTime( timeChar));
		goto error;
	}

	ret = avformat_open_input(&ic, input, NULL, (format_opts) ? &format_opts : NULL);

	if (ret != 0)
	{
		fprintf(stderr,
				"%sCould not open input file, make sure it is an mpegts or mp4 file: %d\n", getSystemTime(timeChar), ret);
		goto error;
	}
	av_dict_free(&format_opts);

	if (avformat_find_stream_info(ic, NULL) < 0)
	{
		fprintf(stderr, "%s Could not read stream information\n", getSystemTime( timeChar));
		goto error;
	}

#if LIBAVFORMAT_VERSION_MAJOR > 52 || (LIBAVFORMAT_VERSION_MAJOR == 52 && \
                                       LIBAVFORMAT_VERSION_MINOR >= 45)
	ofmt = av_guess_format("mpegts", NULL, NULL);
#else
	ofmt = guess_format("mpegts", NULL, NULL);
#endif

	if (!ofmt)
	{
		fprintf(stderr, "%s Could not find MPEG-TS muxer\n", getSystemTime( timeChar));
		goto error;
	}

	oc = avformat_alloc_context();
	if (!oc)
	{
		fprintf(stderr, "%s Could not allocated output context\n", getSystemTime( timeChar));
		goto error;
	}
	oc->oformat = ofmt;

	video_index = -1;
	audio_index = -1;

	for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++)
	{
		switch (ic->streams[i]->codec->codec_type)
		{
		case AVMEDIA_TYPE_VIDEO:
			video_index = i;
			ic->streams[i]->discard = AVDISCARD_NONE;
			video_st = add_output_stream(oc, ic->streams[i]);
			break;
		case AVMEDIA_TYPE_AUDIO:
			audio_index = i;
			ic->streams[i]->discard = AVDISCARD_NONE;
			audio_st = add_output_stream(oc, ic->streams[i]);
			break;
		default:
			ic->streams[i]->discard = AVDISCARD_ALL;
			break;
		}
	}

	av_dump_format(oc, 0, output_prefix, 1);

	if (video_index >= 0)
	{
		codec = avcodec_find_decoder(video_st->codec->codec_id);
		if (!codec)
		{
			fprintf(stderr,
					"%s Could not find video decoder, key frames will not be honored\n", getSystemTime( timeChar));
		}

		if (avcodec_open2(video_st->codec, codec, NULL) < 0)
		{
			fprintf(stderr,
					"%s Could not open video decoder, key frames will not be honored\n", getSystemTime( timeChar));
		}
	}

	snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts",
			output_prefix, output_index);

	if( 1 == if_save_keyframe)
	{ 
		snprintf(keyframeinfo_filename, strlen(output_prefix) + 15,
			"%s-%u.idx", output_prefix, output_index);
		obj = json_object_new_object();
		info_arr_obj = create_json_header(obj);
	}

	if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0)
	{
		fprintf(stderr, "%s Could not open '%s'\n", getSystemTime( timeChar),output_filename);
		goto error;
	}

	if (avformat_write_header(oc, NULL))
	{
		fprintf(stderr, "%s Could not write mpegts header to first output file\n", getSystemTime( timeChar));
		goto error;
	}

	prev_segment_time = (double) (ic->start_time) / (double) (AV_TIME_BASE);

	streamLace = createStreamLace(ic->nb_streams);

	// add by houmr
	int continue_error_cnt = 0;
	//int pushcnt = 0;
	//int popcnt = 0;
	int tscnt = 0;
	int audiopktcnt = 0;
	int videopktcnt = 0;
	int kfcnt = 0;
	int errpktcnt = 0;
	/////////////////////////
	do
	{
		double segment_time = 0.0;
		AVPacket packet;
		double packetStartTime = 0.0;
		double packetDuration = 0.0;

		if (!decode_done)
		{
			//fprintf(stdout, "%s av_read_frame() begin.\n", getSystemTime( timeChar));
			decode_done = av_read_frame(ic, &packet);
			//fprintf(stdout, "%s av_read_frame() end. packet.size=%d stream_index=%d duration=%d\n", getSystemTime( timeChar), packet.size, packet.stream_index, packet.duration);
			//fprintf(stdout, "%s decode_done=%d\n", getSystemTime( timeChar),decode_done);
			if (!decode_done)
			{
				if (packet.stream_index != video_index
						&& packet.stream_index != audio_index)
				{
					if( ++errpktcnt >= 10)
					{
						decode_done = 1;	
					}
					fprintf(stderr, "%s packet is not video or audio, packet.stream_index=%d\n", getSystemTime( timeChar), packet.stream_index);
					av_free_packet(&packet);
					continue;
				}
				errpktcnt = 0;

				/*printf("orgin : index - %d\t pts = %s\t duration=%d\n", packet.stream_index,
				 av_ts2str(packet.pts), packet.duration);*/
				// add by houmr
				/*if (adjust_pts(&packet, video_index, audio_index) < 0)
				{
					av_free_packet(&packet);
					continue;
				}
				*/
				/////////////////////////////////////
				double timeStamp =
						(double) (packet.pts)
								* (double) (ic->streams[packet.stream_index]->time_base.num)
								/ (double) (ic->streams[packet.stream_index]->time_base.den);

				if (av_dup_packet(&packet) < 0)
				{
					fprintf(stderr, "%s Could not duplicate packet\n" ,getSystemTime( timeChar));
					av_free_packet(&packet);
					break;
				}
				
				/*
				for(int i = 0; i < streamLace->numStreams; ++i)
				{ 
						fprintf(stdout, "streamLace[%d].size=%d\t", i, streamLace->streams[i]->size);
				}
				fprintf(stdout, "\n");
				*/
				insertPacket(streamLace, &packet, timeStamp);
			}
		}

		if (countPackets(streamLace) < 50 && !decode_done)
		{
			/* allow the queue to fill up so that the packets can be sorted properly */
			continue;
		}

		if (!removePacket(streamLace, &packet))
		{
			fprintf(stdout, "%s get packet failed!!\n", getSystemTime( timeChar));
			if (decode_done)
			{
				/* the queue is empty, we are done */
				break;
			}

			assert(decode_done);
			continue;
		}

		//fprintf(stdout, "%s get 1 packet success. packet info: pts=%ld, dts=%ld\n", getSystemTime( timeChar), packet.pts, packet.dts);
		packetStartTime = (double) (packet.pts)
				* (double) (ic->streams[packet.stream_index]->time_base.num)
				/ (double) (ic->streams[packet.stream_index]->time_base.den);

		packetDuration = (double) (packet.duration)
				* (double) (ic->streams[packet.stream_index]->time_base.num)
				/ (double) (ic->streams[packet.stream_index]->time_base.den);

#if !defined(NDEBUG) && (defined(DEBUG) || defined(_DEBUG))
		if (av_log_get_level() >= AV_LOG_VERBOSE)
		fprintf(stderr,
				"%s stream %i, packet [%f, %f)\n",
				getSystemTime( timeChar),
				packet.stream_index,
				packetStartTime,
				packetStartTime + packetDuration);
#endif

		segment_duration = packetStartTime + packetDuration - prev_segment_time;

		// NOTE: segments are supposed to start on a keyframe.
		// If the keyframe interval and segment duration do not match
		// forcing the segment creation for "better seeking behavior"
		// will result in decoding artifacts after seeking or stream switching.
		if (packet.stream_index == video_index
				&& (packet.flags & AV_PKT_FLAG_KEY || strict_segment_duration))
		{
			//This is video packet and ( packet is key frame or strict time is needed )
			segment_time = packetStartTime;
		}
		else if (video_index < 0)
		{
			//This stream doesn't contain video stream
			segment_time = packetStartTime;
		}
		else
		{
			//This is a video packet or a video packet but not key frame 
			segment_time = prev_segment_time;
		}

		//fprintf(stdout, "%s extra_duration_needed=%f\n", getSystemTime( timeChar), extra_duration_needed);
		if (segment_time - prev_segment_time + segment_duration_error_tolerance
				> target_segment_duration + extra_duration_needed)
		{
			fprintf(stdout, "%s segment_time=%lf prev_segment_time=%lf  > target_segment_duration=%lf  extra_duration_needed=%lf\n", getSystemTime( timeChar), segment_time, prev_segment_time,  target_segment_duration, extra_duration_needed);
			fprintf(stdout, "%s File %s contains %d PES packet, of which %d are audio packet, %d are video packet within %d key frame.\n", getSystemTime( timeChar), output_filename, tscnt, audiopktcnt, videopktcnt, kfcnt);
			fflush(stdout);
			/*
			for(int i = 0; i < streamLace->numStreams; ++i)
			{
					fprintf(stdout, "%s streamLace[%d].size=%d\t", getSystemTime( timeChar), i, streamLace->streams[i]->size);
			}
			*/
			tscnt = audiopktcnt = videopktcnt = kfcnt = 0;
			avio_flush(oc->pb);
			avio_close(oc->pb);

			// Keep track of accumulated rounding error to account for it in later chunks.
		/*
			double segment_duration = segment_time - prev_segment_time;
			int rounded_segment_duration = (int) (segment_duration + 0.5);
			extra_duration_needed += (double) rounded_segment_duration
					- segment_duration;
		*/
			double seg_dur = segment_time - prev_segment_time;
			int rounded_segment_duration = (int) (seg_dur + 0.5);
			extra_duration_needed += (target_segment_duration - seg_dur - segment_duration_error_tolerance);
			//fprintf(stdout, "%s ________extra_duration_needed = %lf\n", getSystemTime( timeChar), extra_duration_needed);
			

			updatePlaylist(playlist, playlist_filename, output_filename,
					output_index, rounded_segment_duration);

			
			snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts",
					output_prefix, ++output_index);
			//add by wanggm
			//Save the all the keyframe information into json file
			if( 1 == if_save_keyframe && NULL != obj)
			{ 
				save_json_to_file(keyframeinfo_filename, obj);
				obj = info_arr_obj = NULL;

				snprintf(keyframeinfo_filename, strlen(output_prefix) + 15,
					"%s-%u.idx", output_prefix, output_index);
			}


			if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0)
			{
				fprintf(stderr, "%s Could not open '%s'\n", getSystemTime( timeChar), output_filename);
				break;
			}

			// close when we find the 'kill' file
			if (kill_file)
			{
				FILE* fp = fopen("kill", "rb");
				if (fp)
				{
					fprintf(stderr, "%s user abort: found kill file\n", getSystemTime( timeChar));
					fclose(fp);
					remove("kill");
					decode_done = 1;
					removeAllPackets(streamLace);
				}
			}
			prev_segment_time = segment_time;
		}

		//add by wanggm.
		++tscnt;
		if( video_index == packet.stream_index)
		{
			++videopktcnt;	
			if(1 == packet.flags)
			{ 
				++kfcnt;	
				if( 1 == if_save_keyframe)
				{
					//If it is key frame, it's information should be saved.
					//fprintf(stdout, "%s packet is keyframe, packet.pts=%ld\n", getSystemTime( timeChar), packet.pts);
					snprintf(keyframeinfo_filename, strlen(output_prefix) + 15,
					"%s-%u.idx", output_prefix, output_index);
					if (NULL == obj && NULL == info_arr_obj)
					{ 
						obj = json_object_new_object();
						info_arr_obj = create_json_header(obj);
					}
					avio_flush(oc->pb);		//flush the previous data into ts file.
					int64_t offset = avio_tell(oc->pb);	//Get the offset of this key frame in the file.
					save_keyframe_info(info_arr_obj, offset, packet.pts);
					//fprintf(stdout, "%s Keyframe.pos=%ld \tkeyframe.pts=%ld\n", getSystemTime( timeChar), offset, (long)packet.pts);
				}
			}
		}else if( audio_index == packet.stream_index)
		{
			++audiopktcnt;	
		}
		//fprintf(stdout, "%s packet is not keyframe.\n", getSystemTime( timeChar));

		ret = av_interleaved_write_frame(oc, &packet);

		if (ret < 0)
		{
			fprintf(stderr, "%s Warning: Could not write frame of stream\n", getSystemTime( timeChar));
			// add by houmr
			continue_error_cnt++;
			if (continue_error_cnt > 10)
			{
				av_free_packet(&packet);
				break;
			}
		}
		else if (ret > 0)
		{
			fprintf(stderr, "%s End of stream requested\n", getSystemTime( timeChar));
			av_free_packet(&packet);
			break;
		}
		else
		{
			// add by houmr error
			continue_error_cnt = 0;
			////////////////////////
		}
		av_free_packet(&packet);
	} while (!decode_done || countPackets(streamLace) > 0);

	av_write_trailer(oc);

	if (video_index >= 0)
	{
		avcodec_close(video_st->codec);
	}

	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);

	updatePlaylist(playlist, playlist_filename, output_filename, output_index,
			segment_duration);
	closePlaylist(playlist);
	releasePlaylist(&playlist);

	//add by wanggm
	if( 1 == if_save_keyframe && obj != NULL)
	{ 
		save_json_to_file(keyframeinfo_filename, obj);
	}

	if (pid_filename)
	{
		remove(pid_filename);
	}
	
	fflush(stdout);
	fflush(stderr);

	return 0;

	error: if (pid_filename)
	{
		remove(pid_filename);
	}

	return 1;

}