Example #1
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;
}
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 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;
}