From ed3231019fda5f38117f4b4e9f99639420ab4b09 Mon Sep 17 00:00:00 2001 From: Carson McDonald Date: Tue, 19 Jul 2011 10:57:29 -0400 Subject: [PATCH 1/4] Remove unused libraries from compile. Update to compile against latest ffmpeg. Initial attempt at fixing validation errors. --- Makefile | 2 +- live_segmenter.c | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 9ef722f..e3e68b1 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ all: - gcc -Wall -g live_segmenter.c -o live_segmenter -lavformat -lavcodec -lavutil -lbz2 -lm -lz -lfaac -lmp3lame -lx264 -lfaad -lpthread + gcc -Wall -L /usr/lib/ -g live_segmenter.c -o live_segmenter -lavformat -lavcodec -lavutil -lbz2 -lm -lz -lfaac -lmp3lame -lx264 -lfaad -lpthread clean: rm -f live_segmenter diff --git a/live_segmenter.c b/live_segmenter.c index 2485e0e..d08e42d 100644 --- a/live_segmenter.c +++ b/live_segmenter.c @@ -178,6 +178,9 @@ int main(int argc, char **argv) } 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; @@ -227,6 +230,11 @@ int main(int argc, char **argv) } } + if (video_stream->codec->ticks_per_frame > 1) + { + 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 (url_fopen(&output_context->pb, output_filename, URL_WRONLY) < 0) @@ -241,6 +249,10 @@ int main(int argc, char **argv) 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; @@ -264,13 +276,26 @@ int main(int argc, char **argv) break; } - if (packet.stream_index == video_index && (packet.flags & PKT_FLAG_KEY)) + if (packet.stream_index == video_index) { - segment_time = (double)video_stream->pts.val * video_stream->time_base.num / video_stream->time_base.den; - } - else if (video_index < 0) + 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) { - segment_time = (double)audio_stream->pts.val * audio_stream->time_base.num / audio_stream->time_base.den; + 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 { @@ -295,7 +320,7 @@ int main(int argc, char **argv) prev_segment_time = segment_time; } - ret = av_interleaved_write_frame(output_context, &packet); + ret = av_write_frame(output_context, &packet); if (ret < 0) { fprintf(stderr, "Segmenter error: Could not write frame of stream: %d\n", ret); From aa5247032029b8795c5070396806c16c8deaa1d9 Mon Sep 17 00:00:00 2001 From: rdkls Date: Wed, 2 Nov 2011 13:05:12 +1100 Subject: [PATCH 2/4] Updates to work with new versions of libavformat --- live_segmenter.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/live_segmenter.c b/live_segmenter.c index d08e42d..0d0f05c 100644 --- a/live_segmenter.c +++ b/live_segmenter.c @@ -67,7 +67,7 @@ static AVStream *add_output_stream(AVFormatContext *output_format_context, AVStr switch (input_codec_context->codec_type) { - case CODEC_TYPE_AUDIO: + case AVMEDIA_TYPE_AUDIO: output_codec_context->channel_layout = input_codec_context->channel_layout; output_codec_context->sample_rate = input_codec_context->sample_rate; output_codec_context->channels = input_codec_context->channels; @@ -81,7 +81,7 @@ static AVStream *add_output_stream(AVFormatContext *output_format_context, AVStr output_codec_context->block_align = input_codec_context->block_align; } break; - case CODEC_TYPE_VIDEO: + case AVMEDIA_TYPE_VIDEO: output_codec_context->pix_fmt = input_codec_context->pix_fmt; output_codec_context->width = input_codec_context->width; output_codec_context->height = input_codec_context->height; @@ -159,7 +159,7 @@ int main(int argc, char **argv) exit(1); } -#if LIBAVFORMAT_VERSION_MAJOR >= 52 && LIBAVFORMAT_VERSION_MINOR >= 45 +#if LIBAVFORMAT_VERSION_MAJOR > 52 || (LIBAVFORMAT_VERSION_MAJOR == 52 && LIBAVFORMAT_VERSION_MINOR >= 45) AVOutputFormat *output_format = av_guess_format("mpegts", NULL, NULL); #else AVOutputFormat *output_format = guess_format("mpegts", NULL, NULL); @@ -192,12 +192,12 @@ int main(int argc, char **argv) for (i = 0; i < input_context->nb_streams && (video_index < 0 || audio_index < 0); i++) { switch (input_context->streams[i]->codec->codec_type) { - case CODEC_TYPE_VIDEO: + 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 CODEC_TYPE_AUDIO: + 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]); From 3bfe161fa88017f2d3f3ac6798df7a5127fd86a0 Mon Sep 17 00:00:00 2001 From: Thomas Christensen Date: Fri, 9 Dec 2011 21:02:09 +0100 Subject: [PATCH 3/4] Made the sanity check skip udp based input locations Editing Makefile to work on Mac OS X (location of libs) --- Makefile | 2 +- hs_config.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e3e68b1..869bb84 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ all: - gcc -Wall -L /usr/lib/ -g live_segmenter.c -o live_segmenter -lavformat -lavcodec -lavutil -lbz2 -lm -lz -lfaac -lmp3lame -lx264 -lfaad -lpthread + gcc -Wall -L /usr/lib/ -L /usr/local/lib -g live_segmenter.c -o live_segmenter -lavformat -lavcodec -lavutil -lbz2 -lm -lz -lfaac -lmp3lame -lx264 -lfaad -lpthread clean: rm -f live_segmenter diff --git a/hs_config.rb b/hs_config.rb index ead3f98..9babab5 100755 --- a/hs_config.rb +++ b/hs_config.rb @@ -74,7 +74,7 @@ def sanity_check(config) raise end - if !File.readable? config['input_location'] + if !config['input_location'].match(/^udp:/) and !File.readable? config['input_location'] log.error("The input file can not be read: #{config['input_location']}") raise end From 309d015902c69a31482e4b573e60e7568bd5d09d Mon Sep 17 00:00:00 2001 From: Thomas Christensen Date: Sat, 10 Dec 2011 04:40:57 +0100 Subject: [PATCH 4/4] Added a clean up script that can be run from cron. Uses the configuration file. Only works with single profile stream indexes. --- http_cleaner.rb | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 http_cleaner.rb diff --git a/http_cleaner.rb b/http_cleaner.rb new file mode 100644 index 0000000..b6986bf --- /dev/null +++ b/http_cleaner.rb @@ -0,0 +1,74 @@ +#!/usr/bin/env ruby +# +# Copyright (c) 2011 Thomas Christensen +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 2 +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +require 'hs_config' + +if ARGV.length != 1 + puts "Usage: http_cleaner.rb " + exit 1 +end + +begin + config = HSConfig::load( ARGV[0] ) +rescue + exit 1 +end + +log = HSConfig::log_setup( config ) + +log.info('HTTP Cleaner started') + +transfer_config = config[config['transfer_profile']] +streamdir = transfer_config['directory'] + '/' +indexfile = "%s_%s.m3u8" % [config['index_prefix'], config['encoding_profile']] + +latestseq = 0 +latestfile = '' +nextline = 0 + +def purge(dir, pattern, timestamp) + puts 'Deleting '+pattern+' files in '+dir+' older than ' + puts timestamp + Dir.chdir(dir) + Dir.glob(pattern).each do|f| + curts = File.mtime(f) + if curts < timestamp and !File.directory?(f) + puts 'Purging '+f + File.delete(f) + end + end +end + +File.open(streamdir+indexfile).each do |line| + if nextline == 1 and latestfile == '' + latestfile = line.strip + nextline = 0 + end + if line[/#EXTINF:5,/] + nextline = 1 + end +end +puts 'Looking for time stamp on '+streamdir+latestfile + +# Create file name + +lastchange = File.mtime(streamdir+latestfile) +purge(streamdir,'*.ts',lastchange) + +log.info('HTTP Cleaner stopped') + +