diff options
Diffstat (limited to 'src/demuxers/demux_mpeg_pes.c')
-rw-r--r-- | src/demuxers/demux_mpeg_pes.c | 206 |
1 files changed, 99 insertions, 107 deletions
diff --git a/src/demuxers/demux_mpeg_pes.c b/src/demuxers/demux_mpeg_pes.c index c5769e3e3..f5d554020 100644 --- a/src/demuxers/demux_mpeg_pes.c +++ b/src/demuxers/demux_mpeg_pes.c @@ -15,9 +15,7 @@ * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id: demux_mpeg_pes.c,v 1.43 2007/03/29 17:11:36 dgp85 Exp $ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * demultiplexer for mpeg 2 PES (Packetized Elementary Streams) * reads streams of variable blocksizes @@ -25,7 +23,6 @@ * 1-7-2003 New implementation of mpeg 2 PES demuxers. * (c) 2003 James Courtier-Dutton James@superbug.demon.co.uk * This code might also decode normal MPG files. - * */ #ifdef HAVE_CONFIG_H @@ -44,9 +41,9 @@ #define LOG */ -#include "xine_internal.h" -#include "xineutils.h" -#include "demux.h" +#include <xine/xine_internal.h> +#include <xine/xineutils.h> +#include <xine/demux.h> #define NUM_PREVIEW_BUFFERS 250 #define DISC_TRESHOLD 90000 @@ -136,13 +133,79 @@ static int32_t parse_IEC14496_FlexMux_stream(demux_mpeg_pes_t *this, uint8_t *p, static int32_t parse_program_stream_directory(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf); static int32_t parse_program_stream_pack_header(demux_mpeg_pes_t *this, uint8_t *p, buf_element_t *buf); -static void check_newpts( demux_mpeg_pes_t *this, int64_t pts, int video ) +static int detect_pts_discontinuity( demux_mpeg_pes_t *this, int64_t pts, int video ) { int64_t diff; - + + /* discontinuity detection is difficult to implement in the demuxer as it gets + * for example video packets in decoding order and there can be multiple audio + * and video tracks. So for simplicity, let's just deal with a single audio and + * a single video track. + * + * To start with, let's have a look at the audio and video track independently. + * Whenever pts differs from last_pts[video] by at least WRAP_THRESHOLD, a jump + * in pts is detected. Such a jump can happen for example when the pts counter + * overflows, as shown below (video decoding order ignored for simplicity; the + * variable values are shown after returning from the below function check_newpts; + * an asterisk means that this value has been cleared (see check_newpts)): + * + * pts: 7v 7a 8v 9v 9a : 0v 1v 1a 2v 3v 3a 4v + * last_pts[0]: 6 7 7 7 9 : * * 1 1 1 3 3 + * last_pts[1]: 7 7 8 9 9 : 0 1 1 2 3 3 4 + * | | | + * | | +--- audio pts wrap ignored + * | +--------- video pts wrap detected + * +----------- pts wrap boundary + */ diff = pts - this->last_pts[video]; - - if( pts && (this->send_newpts || (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD) ) ) { + + if (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD) + return 1; + + /* but the above code can cause a huge delay while replaying when audio and video + * track are not aligned on a common pts wrap boundery, as shown below: + * + * pts: 7v 8v 7a 9v : 0v 9a 1v 2v : 1a 3v 4v 3a + * last_pts[0]: 6 6 7 7 : * 9 9 9 : 1 1 1 3 + * last_pts[1]: 7 8 8 9 : 0 0 1 2 : * 3 4 4 + * | | | | | + * | | | | +--- audio pts wrap detected + * | | | +----- audio pts wrap boundary + * | | +-------------- audio packet causes a huge delay + * | +----------------- video pts wrap detected + * +------------------- video pts wrap boundery + * + * So there is the need to compare audio track pts against video track pts + * to detect when pts values are in between pts wrap bounderies, where a + * jump needs to be detected too, as shown below: + * + * pts: 7v 8v 7a 9v : 0v 9a 1v 2v : 1a 3v 4v 3a + * last_pts[0]: 6 6 7 7 : * 9 * * : 1 1 1 3 + * last_pts[1]: 7 8 8 9 : 0 * 1 2 : 2 3 4 4 + * | | | | | | + * | | | | | +--- (audio pts wrap ignored) + * | | | | +----- audio pts wrap boundary + * | | | +----------- video pts wrap detected + * | | +-------------- audio pts wrap detected + * | +----------------- video pts wrap detected + * +------------------- (video pts wrap boundery) + * + * Basically, it's almost the same test like above, but against the other track's + * pts value and with a different limit. As the pts counter is a 33 bit unsigned + * integer, we choose 2^31 as limit (2^32 would require the tracks to be aligned). + */ + diff = pts - this->last_pts[1-video]; + + if (this->last_pts[1-video] && abs(diff)>(1u<<31)) + return 1; + + /* no discontinuity detected */ + return 0; +} + +static void check_newpts( demux_mpeg_pes_t *this, int64_t pts, int video ) +{ + if( pts && (this->send_newpts || detect_pts_discontinuity(this, pts, video) ) ) { /* check if pts is outside nav pts range. any stream without nav must enter here. */ if( pts > this->nav_last_end_pts || pts < this->nav_last_start_pts ) @@ -159,47 +222,13 @@ static void check_newpts( demux_mpeg_pes_t *this, int64_t pts, int video ) } else { lprintf("no wrap detected\n" ); } - + + /* clear pts on the other track to avoid detecting the same discontinuity again */ this->last_pts[1-video] = 0; } if( pts ) - { - /* don't detect a discontinuity only for video respectively audio. It's also a discontinuity - indication when audio and video pts differ to much e. g. when a pts wrap happens. - The original code worked well when the wrap happend like this: - - V7 A7 V8 V9 A9 Dv V0 V1 da A1 V2 V3 A3 V4 - - Legend: - Vn = video packet with timestamp n - An = audio packet with timestamp n - Dv = discontinuity detected on following video packet - Da = discontinuity detected on following audio packet - dv = discontinuity detected on following video packet but ignored - da = discontinuity detected on following audio packet but ignored - - But with a certain delay between audio and video packets (e. g. the way DVB-S broadcasts - the packets) the code didn't work: - - V7 V8 A7 V9 Dv V0 _A9_ V1 V2 Da _A1_ V3 V4 A3 - - Packet A9 caused audio to jump forward and A1 caused it to jump backward with inserting - a delay of almoust 26.5 hours! - - The new code gives the following sequences for the above examples: - - V7 A7 V8 V9 A9 Dv V0 V1 A1 V2 V3 A3 V4 - - V7 V8 A7 V9 Dv V0 Da A9 Dv V1 V2 A1 V3 V4 A3 - - After proving this code it should be cleaned up to use just a single variable "last_pts". */ - -/* this->last_pts[video] = pts; -*/ - this->last_pts[video] = this->last_pts[1-video] = pts; - } } static off_t read_data(demux_mpeg_pes_t *this, uint8_t *buf, off_t nlen) @@ -1110,7 +1139,7 @@ static int32_t parse_video_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_elemen uint8_t *pp = p + 2, *pp_limit = p + payload_size - 1; while (0 < pp && pp < pp_limit) { if (pp[0] == 0x01 && pp[-1] == 0x00 && pp[-2] == 0x00) { - if (pp[1] >= 0x80) { /* MPEG 1/2 start code */ + if (pp[1] >= 0x80 || !pp[1]) { /* MPEG 1/2 start code */ this->mpeg12_h264_detected = 2; break; } else { @@ -1135,17 +1164,20 @@ static int32_t parse_video_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_elemen */ if (this->mpeg12_h264_detected & 1) { buf_type = BUF_VIDEO_H264; - int nal_type_code = -1; - if (payload_size >= 4 && p[2] == 0x01 && p[1] == 0x00 && p[0] == 0x00) - nal_type_code = p[3] & 0x1f; - if (nal_type_code == 9) { /* access unit delimiter */ - buf_element_t *b = this->video_fifo->buffer_pool_alloc (this->video_fifo); - b->content = b->mem; - b->size = 0; - b->pts = 0; - b->type = buf_type; - b->decoder_flags = BUF_FLAG_FRAME_END; - this->video_fifo->put (this->video_fifo, b); + /* omit sending BUF_FLAG_FRAME_END for the first AUD occurence */ + if (this->mpeg12_h264_detected > 2) { + int nal_type_code = -1; + if (payload_size >= 4 && p[2] == 0x01 && p[1] == 0x00 && p[0] == 0x00) + nal_type_code = p[3] & 0x1f; + if (nal_type_code == 9) { /* access unit delimiter */ + buf_element_t *b = this->video_fifo->buffer_pool_alloc (this->video_fifo); + b->content = b->mem; + b->size = 0; + b->pts = 0; + b->type = buf_type; + b->decoder_flags = BUF_FLAG_FRAME_END; + this->video_fifo->put (this->video_fifo, b); + } } } @@ -1694,25 +1726,8 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str } break; - case METHOD_BY_EXTENSION: { - const char *const mrl = input->get_mrl (input); - const char *const ending = strrchr(mrl, '.'); - - if (!ending) { - free (this->scratch_base); - free (this); - return NULL; - } - - if (strncasecmp(ending, ".MPEG", 5) - && strncasecmp (ending, ".vdr", 4) - && strncasecmp (ending, ".mpg", 4)) { - free (this->scratch_base); - free (this); - return NULL; - } - } - break; + case METHOD_BY_MRL: + break; case METHOD_EXPLICIT: { @@ -1728,29 +1743,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return &this->demux_plugin; } -static const char *get_description (demux_class_t *this_gen) { - return "mpeg pes demux plugin"; -} - -static const char *get_identifier (demux_class_t *this_gen) { - return "MPEG_PES"; -} - -static const char *get_extensions (demux_class_t *this_gen) { - return "pes"; -} - -static const char *get_mimetypes (demux_class_t *this_gen) { - return NULL; -} - -static void class_dispose (demux_class_t *this_gen) { - - demux_mpeg_pes_class_t *this = (demux_mpeg_pes_class_t *) this_gen; - - free (this); - } - static void *init_plugin (xine_t *xine, void *data) { demux_mpeg_pes_class_t *this; @@ -1759,11 +1751,11 @@ static void *init_plugin (xine_t *xine, void *data) { this->xine = xine; this->demux_class.open_plugin = open_plugin; - this->demux_class.get_description = get_description; - this->demux_class.get_identifier = get_identifier; - this->demux_class.get_mimetypes = get_mimetypes; - this->demux_class.get_extensions = get_extensions; - this->demux_class.dispose = class_dispose; + this->demux_class.description = N_("mpeg pes demux plugin"); + this->demux_class.identifier = "MPEG_PES"; + this->demux_class.mimetypes = NULL; + this->demux_class.extensions = "pes vdr:/ netvdr:/"; + this->demux_class.dispose = default_demux_class_dispose; return this; } @@ -1777,6 +1769,6 @@ static const demuxer_info_t demux_info_mpeg_pes = { const plugin_info_t xine_plugin_info[] EXPORTED = { /* type, API, "name", version, special_info, init_function */ - { PLUGIN_DEMUX, 26, "mpeg_pes", XINE_VERSION_CODE, &demux_info_mpeg_pes, init_plugin }, + { PLUGIN_DEMUX, 27, "mpeg_pes", XINE_VERSION_CODE, &demux_info_mpeg_pes, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; |