summaryrefslogtreecommitdiff
path: root/xine/demux_xvdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'xine/demux_xvdr.c')
-rw-r--r--xine/demux_xvdr.c1234
1 files changed, 0 insertions, 1234 deletions
diff --git a/xine/demux_xvdr.c b/xine/demux_xvdr.c
deleted file mode 100644
index e68dfa5c..00000000
--- a/xine/demux_xvdr.c
+++ /dev/null
@@ -1,1234 +0,0 @@
-/*
- * Copyright (C) 2000-2006 the xine project
- *
- * This file is part of xine, a free video player.
- *
- * xine is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * xine 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, USA
- *
- * demultiplexer for xineliboutput (xvdr)
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <xine/xine_internal.h>
-#include <xine/xineutils.h>
-#include <xine/demux.h>
-
-#include "../xine_input_vdr_mrl.h"
-#include "../tools/mpeg.h"
-#include "../tools/h264.h"
-#include "../tools/pes.h"
-#include "../tools/ts.h"
-
-#include "ts2es.h"
-#include "demux_xvdr_tsdata.h"
-
-/*
- * features
- */
-
-#define VDR_SUBTITLES
-#define TEST_DVB_SPU
-
-/*
- * logging
- */
-
-static const char log_module_demux_xvdr[] = "[demux_vdr] ";
-#define LOG_MODULENAME log_module_demux_xvdr
-#define SysLogLevel iSysLogLevel
-
-#include "../logdefs.h"
-
-#define LOGSPU(x...)
-
-/*
- * constants
- */
-
-#define DISC_TRESHOLD 90000
-#define WRAP_THRESHOLD 120000
-#define PTS_AUDIO 0
-#define PTS_VIDEO 1
-
-
-/* redefine abs as macro to handle 64-bit diffs.
- i guess llabs may not be available everywhere */
-#define abs(x) ( ((x)<0) ? -(x) : (x) )
-
-typedef struct demux_xvdr_s {
- demux_plugin_t demux_plugin;
-
- xine_stream_t *stream;
- fifo_buffer_t *audio_fifo;
- fifo_buffer_t *video_fifo;
-
- input_plugin_t *input;
-
- ts_data_t *ts_data; /* MPEG-TS stuff */
-
- int64_t last_pts[2];
- int64_t last_vpts;
- int status;
- uint32_t video_type;
- uint32_t audio_type;
- uint32_t subtitle_type;
-
- /* current buf_element */
- int64_t pts;
- int64_t dts;
- uint32_t packet_len;
- uint8_t stream_id;
-
- uint8_t send_newpts : 1;
- uint8_t buf_flag_seek : 1;
- uint8_t ffmpeg_mpeg2_decoder : 1;
- uint8_t coreavc_h264_decoder : 1;
- uint8_t bih_posted : 1;
-} demux_xvdr_t ;
-
-typedef struct {
-
- demux_class_t demux_class;
-
- /* class-wide, global variables here */
-
- xine_t *xine;
- config_values_t *config;
-} demux_xvdr_class_t;
-
-
-static const char * get_decoder_name(xine_t *xine, int video_type)
-{
- int streamtype = (video_type >> 16) & 0xFF;
- plugin_node_t *node = xine->plugin_catalog->video_decoder_map[streamtype][0];
- if (node) {
- plugin_info_t *info = node->info;
- if (info)
- return info->id;
- }
- return "";
-}
-
-static void detect_video_decoders(demux_xvdr_t *this)
-{
- if (!strcmp(get_decoder_name(this->stream->xine, BUF_VIDEO_MPEG), "ffmpegvideo"))
- this->ffmpeg_mpeg2_decoder = 1;
- LOGMSG("Using decoder \"%s\" for mpeg2 video",
- this->ffmpeg_mpeg2_decoder ? "FFmpeg" : "libmpeg2");
-
- if (!strcmp(get_decoder_name(this->stream->xine, BUF_VIDEO_H264), "dshowserver"))
- this->coreavc_h264_decoder = 1;
- LOGMSG("Using decoder \"%s\" for H.264 video",
- this->coreavc_h264_decoder ? "dshowserver (CoreAVC)" : "FFmpeg");
-}
-
-static void demux_xvdr_parse_ts(demux_xvdr_t *this, buf_element_t *buf);
-static void demux_xvdr_parse_pes(demux_xvdr_t *this, buf_element_t *buf);
-
-static int32_t parse_video_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf);
-static int32_t parse_audio_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf);
-static int32_t parse_private_stream_1(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf);
-static int32_t parse_padding_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf);
-
-static void pts_wrap_workaround(demux_xvdr_t *this, buf_element_t *buf, int video)
-{
-#ifdef LOG_PES_AV_DIFF
- static int64_t vpts = 0, apts = 0;
- if (video) vpts = buf->pts;
- else apts = buf->pts;
- if (vpts > 0 && apts > 0)
- LOGMSG("pts diff [%d] %d", video, (int)(vpts - apts));
-#endif
-
- /* PTS wrap workaround */
- if (buf->pts >= 0) {
- if (video)
- this->last_vpts = buf->pts;
- else if (buf->pts > INT64_C( 0x40400000 ) &&
- this->last_vpts < INT64_C( 0x40000000 ) &&
- this->last_vpts > INT64_C( 0 )) {
- LOGMSG("VIDEO pts wrap before AUDIO, ignoring audio pts %" PRId64, buf->pts);
- buf->pts = INT64_C(0);
- }
- }
-}
-
-static void check_newpts(demux_xvdr_t *this, buf_element_t *buf, int video )
-{
- pts_wrap_workaround(this, buf, video);
-
- if (buf->pts) {
- int64_t diff = buf->pts - this->last_pts[video];
-
- if (this->send_newpts || (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD)) {
-
- if (this->buf_flag_seek) {
- _x_demux_control_newpts(this->stream, buf->pts, BUF_FLAG_SEEK);
- this->buf_flag_seek = 0;
- } else {
- _x_demux_control_newpts(this->stream, buf->pts, 0);
- }
- this->send_newpts = 0;
-
- this->last_pts[1-video] = 0;
- }
-
- this->last_pts[video] = buf->pts;
- }
-}
-
-static void put_control_buf(fifo_buffer_t *buffer, fifo_buffer_t *pool, int cmd)
-{
- buf_element_t *buf = pool->buffer_pool_try_alloc(pool);
- if(buf) {
- buf->type = cmd;
- buffer->put(buffer, buf);
- }
-}
-
-/*
- * post_sequence_end()
- *
- * Add MPEG2 or H.264 sequence end code to fifo buffer
- */
-static void post_sequence_end(fifo_buffer_t *fifo, uint32_t video_type)
-{
- buf_element_t *buf = fifo->buffer_pool_try_alloc(fifo);
- if (buf) {
- buf->type = video_type;
- buf->size = 4;
- buf->decoder_flags = BUF_FLAG_FRAME_END;
- buf->content[0] = 0x00;
- buf->content[1] = 0x00;
- buf->content[2] = 0x01;
- buf->content[3] = (video_type == BUF_VIDEO_H264) ? NAL_END_SEQ : 0xB7;
- fifo->put(fifo, buf);
- }
-}
-
-/*
- * post_frame_end()
- *
- * Signal end of video frame to decoder.
- *
- * This function is used with:
- * - FFmpeg mpeg2 decoder
- * - FFmpeg and CoreAVC H.264 decoders
- * - NOT with libmpeg2 mpeg decoder
- */
-static void post_frame_end(demux_xvdr_t *this, buf_element_t *vid_buf)
-{
- buf_element_t *cbuf = this->video_fifo->buffer_pool_try_alloc (this->video_fifo) ?:
- this->audio_fifo->buffer_pool_try_alloc (this->audio_fifo);
-
- if (!cbuf) {
- LOGMSG("post_frame_end(): buffer_pool_try_alloc() failed, retrying");
- xine_usec_sleep (10*1000);
- cbuf = this->video_fifo->buffer_pool_try_alloc (this->video_fifo);
- if (!cbuf) {
- LOGERR("post_frame_end(): get_buf_element() failed !");
- return;
- }
- }
-
- cbuf->type = this->video_type;
- cbuf->decoder_flags = BUF_FLAG_FRAME_END;
-
- if (!this->bih_posted) {
- video_size_t size = {0};
- if (pes_get_video_size(vid_buf->content, vid_buf->size, &size, this->video_type == BUF_VIDEO_H264)) {
-
- /* reset decoder buffer */
- cbuf->decoder_flags |= BUF_FLAG_FRAME_START;
-
- /* Fill xine_bmiheader for CoreAVC / H.264 */
-
- if (this->video_type == BUF_VIDEO_H264 && this->coreavc_h264_decoder) {
- xine_bmiheader *bmi = (xine_bmiheader*) cbuf->content;
-
- cbuf->decoder_flags |= BUF_FLAG_HEADER;
- cbuf->decoder_flags |= BUF_FLAG_STDHEADER; /* CoreAVC: buffer contains bmiheader */
- cbuf->size = sizeof(xine_bmiheader);
-
- memset (bmi, 0, sizeof(xine_bmiheader));
-
- bmi->biSize = sizeof(xine_bmiheader);
- bmi->biWidth = size.width;
- bmi->biHeight = size.height;
-
- bmi->biPlanes = 1;
- bmi->biBitCount = 24;
- bmi->biCompression = 0x34363248;
- bmi->biSizeImage = 0;
- bmi->biXPelsPerMeter = size.pixel_aspect.num;
- bmi->biYPelsPerMeter = size.pixel_aspect.den;
- bmi->biClrUsed = 0;
- bmi->biClrImportant = 0;
- }
-
- /* Set aspect ratio for ffmpeg mpeg2 / CoreAVC H.264 decoder
- * (not for FFmpeg H.264 or libmpeg2 mpeg2 decoders)
- */
-
- if (size.pixel_aspect.num &&
- (this->video_type != BUF_VIDEO_H264 || this->coreavc_h264_decoder)) {
- cbuf->decoder_flags |= BUF_FLAG_HEADER;
- cbuf->decoder_flags |= BUF_FLAG_ASPECT;
- /* pixel ratio -> frame ratio */
- if (size.pixel_aspect.num > size.height) {
- cbuf->decoder_info[1] = size.pixel_aspect.num / size.height;
- cbuf->decoder_info[2] = size.pixel_aspect.den / size.width;
- } else {
- cbuf->decoder_info[1] = size.pixel_aspect.num * size.width;
- cbuf->decoder_info[2] = size.pixel_aspect.den * size.height;
- }
- }
-
- LOGDBG("post_frame_end: video width %d, height %d, pixel aspect %d:%d",
- size.width, size.height, size.pixel_aspect.num, size.pixel_aspect.den);
-
- this->bih_posted = 1;
- }
- }
-
- this->video_fifo->put (this->video_fifo, cbuf);
-}
-
-static void track_audio_stream_change(demux_xvdr_t *this, buf_element_t *buf)
-{
-#if !defined(BUF_CONTROL_RESET_TRACK_MAP)
-# warning xine-lib is older than 1.1.2. Multiple audio streams are not supported.
-#else
- if (this->audio_type != buf->type) {
- LOGDBG("audio stream changed: %08x -> %08x", this->audio_type, buf->type);
- this->audio_type = buf->type;
- put_control_buf(this->audio_fifo,
- this->audio_fifo,
- BUF_CONTROL_RESET_TRACK_MAP);
- }
-#endif
-}
-
-static void demux_xvdr_fwd_buf(demux_xvdr_t *this, buf_element_t *buf)
-{
- /* demuxed video --> video_fifo */
- if ((buf->type & BUF_MAJOR_MASK) == BUF_VIDEO_BASE) {
- this->video_type = buf->type;
- check_newpts (this, buf, PTS_VIDEO);
- this->video_fifo->put (this->video_fifo, buf);
- return;
- }
-
- /* demuxed audio --> audio_fifo */
- if ((buf->type & BUF_MAJOR_MASK) == BUF_AUDIO_BASE) {
- if (this->audio_fifo) {
- check_newpts (this, buf, PTS_AUDIO);
- track_audio_stream_change (this, buf);
- this->audio_fifo->put (this->audio_fifo, buf);
- } else {
- buf->free_buffer (buf);
- }
- return;
- }
-
- /* decoder flush --> video_fifo */
- if (buf->type == BUF_CONTROL_FLUSH_DECODER) {
- /* append sequence end code */
- post_sequence_end (this->video_fifo, this->video_type);
- this->video_fifo->put (this->video_fifo, buf);
- return;
- }
-
- /* control buffer --> both fifos */
- if ((buf->type & BUF_MAJOR_MASK) == BUF_CONTROL_BASE) {
- if (this->audio_fifo) {
- /* duplicate goes to audio fifo */
- buf_element_t *cbuf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
- cbuf->type = buf->type;
- cbuf->decoder_flags = buf->decoder_flags;
- memcpy (cbuf->decoder_info, buf->decoder_info, sizeof(cbuf->decoder_info));
- memcpy (cbuf->decoder_info_ptr, buf->decoder_info_ptr, sizeof(cbuf->decoder_info_ptr));
-
- this->audio_fifo->put (this->audio_fifo, cbuf);
- }
- this->video_fifo->put (this->video_fifo, buf);
- return;
- }
-
- LOGMSG("Unhandled buffer type %08x", buf->type);
- buf->free_buffer (buf);
-}
-
-static void demux_xvdr_parse_pack (demux_xvdr_t *this)
-{
- buf_element_t *buf = NULL;
- uint8_t *p;
-
- buf = this->input->read_block (this->input, this->video_fifo, 8128);
-
- if (!buf) {
- if (errno == EINTR) {
- /* very verbose logging ? */
- if (iSysLogLevel >= SYSLOGLEVEL_VERBOSE)
- LOGDBG("input->read_block() was interrupted");
- } else if (errno != EAGAIN) {
- LOGDBG("DEMUX_FINISHED (input returns NULL with error)");
- this->status = DEMUX_FINISHED;
- ts_data_dispose(&this->ts_data);
- }
- return;
- }
-
- /* If this is not a block for the demuxer, pass it
- * straight through. */
- if (buf->type != BUF_DEMUX_BLOCK) {
- ts_data_flush (this->ts_data);
- demux_xvdr_fwd_buf (this, buf);
- return;
- }
-
- p = buf->content; /* len = this->blocksize; */
- buf->decoder_flags = 0;
-
- if (DATA_IS_TS(p)) {
- demux_xvdr_parse_ts (this, buf);
- return;
- }
- if (DATA_IS_PES(p)) {
- demux_xvdr_parse_pes (this, buf);
- return;
- }
-
- LOGMSG("Header %02x %02x %02x (should be 0x000001 or 0x47)", p[0], p[1], p[2]);
- buf->free_buffer (buf);
- return;
-}
-
-static void demux_xvdr_parse_pes (demux_xvdr_t *this, buf_element_t *buf)
-{
- uint8_t *p = buf->content;
- int32_t result;
-
- this->stream_id = p[3];
-
- if (IS_VIDEO_PACKET(p)) {
- result = parse_video_stream(this, p, buf);
- } else if (IS_MPEG_AUDIO_PACKET(p)) {
- result = parse_audio_stream(this, p, buf);
- } else if (IS_PADDING_PACKET(p)) {
- result = parse_padding_stream(this, p, buf);
- } else if (IS_PS1_PACKET(p)) {
- result = parse_private_stream_1(this, p, buf);
- } else {
- LOGMSG("Unrecognised PES stream 0x%02x", this->stream_id);
- buf->free_buffer (buf);
- return;
- }
-
- if (result < 0) {
- return;
- }
-
- LOGMSG("error! freeing buffer.");
- buf->free_buffer (buf);
-}
-
-/*
- * demux_xvdr_parse_ts()
- *
- * MPEG-TS demuxing
- */
-static void demux_xvdr_parse_ts (demux_xvdr_t *this, buf_element_t *buf)
-{
- if (!this->ts_data)
- this->ts_data = calloc(1, sizeof(ts_data_t));
-
- ts_data_t *ts_data = this->ts_data;
- fifo_buffer_t *src_fifo = buf->source;
-
- while (buf->size >= TS_SIZE) {
-
- unsigned int ts_pid = ts_PID(buf->content);
-
- /* parse PAT */
- if (ts_pid == 0) {
- pat_data_t pat;
-
- ts_data_flush(ts_data);
-
- if (ts_parse_pat(&pat, buf->content)) {
- ts_data->pmt_pid = pat.pmt_pid[0];
- ts_data->program_number = pat.program_number[0];
- if (iSysLogLevel >= SYSLOGLEVEL_VERBOSE)
- LOGDBG("Got PAT, PMT pid = %d, program = %d", ts_data->pmt_pid, ts_data->program_number);
- }
- }
-
- /* parse PMT */
- else if (ts_pid == ts_data->pmt_pid) {
-
- ts_data_flush(ts_data);
-
- if (ts_parse_pmt(&ts_data->pmt, ts_data->program_number, buf->content)) {
-
- /* PMT changed, reset ts->es converters */
- LOGMSG("PMT changed");
- ts_data_ts2es_init(&ts_data, this->stream->video_fifo, this->stream->audio_fifo);
-
- this->video_type = (ts_data->pmt.video_type == ISO_14496_PART10_VIDEO) ?
- BUF_VIDEO_H264 : BUF_VIDEO_MPEG;
-
- /* Inform UI of channels changes */
- xine_event_t event;
- event.type = XINE_EVENT_UI_CHANNELS_CHANGED;
- event.data_length = 0;
- xine_event_send(this->stream, &event);
- }
- }
-
- /* demux video */
- else if (ts_pid == ts_data->pmt.video_pid) {
- if (ts_data->video) {
- buf_element_t *vbuf = ts2es_put(ts_data->video, buf->content, src_fifo);
- if (vbuf) {
- this->pts = vbuf->pts;
- check_newpts( this, vbuf, PTS_VIDEO );
-
- this->stream->video_fifo->put(this->stream->video_fifo, vbuf);
- }
- }
- }
-
- /* demux audio */
- else {
- int i, done = 0;
- for (i=0; i < ts_data->pmt.audio_tracks_count; i++)
- if (ts_pid == ts_data->pmt.audio_tracks[i].pid) {
- if (ts_data->audio[i]) {
- buf_element_t *abuf = ts2es_put(ts_data->audio[i], buf->content, src_fifo);
- if (abuf) {
- this->pts = abuf->pts;
- check_newpts( this, abuf, PTS_AUDIO );
- track_audio_stream_change (this, abuf);
-
- this->stream->audio_fifo->put(this->stream->audio_fifo, abuf);
- }
- }
- done = 1;
- break;
- }
-#if 0
- /* demux subtitles */
- if (!done)
- for (i=0; i < ts_data->pmt.spu_tracks_count; i++)
- if (ts_pid == ts_data->pmt.spu_tracks[i].pid) {
- if (ts_data->spu[i]) {
- buf_element_t *sbuf = ts2es_put(ts_data->spu[i], buf->content, NULL);
- if (sbuf)
- this->stream->video_fifo->put(this->stream->video_fifo, sbuf);
- }
- done = 1;
- break;
- }
-
- if (!done)
- LOGMSG("Got unknown TS packet, pid = %d", ts_pid);
-#endif
- }
-
- buf->content += TS_SIZE;
- buf->size -= TS_SIZE;
- }
-
- buf->free_buffer(buf);
-}
-
-static int32_t parse_padding_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf)
-{
- buf->free_buffer (buf);
- return -1;
-}
-
-/* FIXME: Extension data is not parsed, and is also not skipped. */
-
-static int32_t parse_pes_for_pts(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf)
-{
- int32_t header_len;
-
- this->packet_len = p[4] << 8 | p[5];
-
- if ((p[6] & 0xC0) != 0x80 /* mpeg1 */) {
- header_len = 6;
- p += 6; /* packet_len -= 6; */
-
- while ((p[0] & 0x80) == 0x80) {
- p++;
- header_len++;
- this->packet_len--;
- }
-
- if ((p[0] & 0xc0) == 0x40) {
- /* STD_buffer_scale, STD_buffer_size */
- p += 2;
- header_len += 2;
- this->packet_len -= 2;
- }
-
- this->pts = 0;
- this->dts = 0;
-
- if ((p[0] & 0xf0) == 0x20) {
- this->pts = (int64_t)(p[ 0] & 0x0E) << 29 ;
- this->pts |= p[ 1] << 22 ;
- this->pts |= (p[ 2] & 0xFE) << 14 ;
- this->pts |= p[ 3] << 7 ;
- this->pts |= (p[ 4] & 0xFE) >> 1 ;
- p += 5;
- header_len+= 5;
- this->packet_len -=5;
- return header_len;
- } else if ((p[0] & 0xf0) == 0x30) {
- this->pts = (int64_t)(p[ 0] & 0x0E) << 29 ;
- this->pts |= p[ 1] << 22 ;
- this->pts |= (p[ 2] & 0xFE) << 14 ;
- this->pts |= p[ 3] << 7 ;
- this->pts |= (p[ 4] & 0xFE) >> 1 ;
-
- this->dts = (int64_t)(p[ 5] & 0x0E) << 29 ;
- this->dts |= p[ 6] << 22 ;
- this->dts |= (p[ 7] & 0xFE) << 14 ;
- this->dts |= p[ 8] << 7 ;
- this->dts |= (p[ 9] & 0xFE) >> 1 ;
-
- p += 10;
- header_len += 10;
- this->packet_len -= 10;
- return header_len;
- } else {
- p++;
- header_len++;
- this->packet_len--;
- return header_len;
- }
-
- } else { /* mpeg 2 */
-
-
- if ((p[6] & 0xC0) != 0x80) {
- LOGMSG("warning: PES header reserved 10 bits not found");
- buf->free_buffer(buf);
- return -1;
- }
-
-
- /* check PES scrambling_control */
- if ((p[6] & 0x30) != 0) {
- LOGMSG("encrypted PES ?");
- buf->free_buffer(buf);
- return -1;
- }
-
- if (p[7] & 0x80) { /* pts avail */
-
- this->pts = (int64_t)(p[ 9] & 0x0E) << 29 ;
- this->pts |= p[10] << 22 ;
- this->pts |= (p[11] & 0xFE) << 14 ;
- this->pts |= p[12] << 7 ;
- this->pts |= (p[13] & 0xFE) >> 1 ;
-
- } else
- this->pts = 0;
-
- if (p[7] & 0x40) { /* dts avail */
-
- this->dts = (int64_t)(p[14] & 0x0E) << 29 ;
- this->dts |= p[15] << 22 ;
- this->dts |= (p[16] & 0xFE) << 14 ;
- this->dts |= p[17] << 7 ;
- this->dts |= (p[18] & 0xFE) >> 1 ;
-
- } else
- this->dts = 0;
-
-
- header_len = p[8];
-
- this->packet_len -= header_len + 3;
- return header_len + 9;
- }
- return 0;
-}
-
-#if defined(TEST_DVB_SPU)
-/*
- * parse_dvb_spu()
- *
- * DVB subtitle stream demuxing
- */
-static int32_t parse_dvb_spu(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf, int substream_header_len)
-{
- uint spu_id = p[0] & 0x1f;
- _x_select_spu_channel(this->stream, spu_id);
-
-# ifdef VDR_SUBTITLES
- if (substream_header_len == 1) {
- p--;
- this->packet_len++;
- }
-# endif /* VDR_SUBTITLES */
-
- /* Skip substream header */
- p += substream_header_len;
- buf->content = p;
- buf->size = this->packet_len - substream_header_len;
-
- /* Special buffer when payload packet changes */
- if (this->pts > 0) {
- buf_element_t *cbuf = this->video_fifo->buffer_pool_alloc(this->video_fifo);
- int page_id = (*(p+4) << 8) | *(p+5);
-
- spu_dvb_descriptor_t *spu_descriptor = (spu_dvb_descriptor_t *) cbuf->content;
- memset(spu_descriptor, 0, sizeof(spu_dvb_descriptor_t));
- spu_descriptor->comp_page_id = page_id;
-
- cbuf->type = BUF_SPU_DVB + spu_id;
- cbuf->size = 0;
- cbuf->decoder_flags = BUF_FLAG_SPECIAL;
- cbuf->decoder_info[1] = BUF_SPECIAL_SPU_DVB_DESCRIPTOR;
- cbuf->decoder_info[2] = sizeof(spu_dvb_descriptor_t);
- cbuf->decoder_info_ptr[2] = spu_descriptor;
-
- this->video_fifo->put (this->video_fifo, cbuf);
- }
-
- buf->type = BUF_SPU_DVB + spu_id;
- buf->pts = this->pts;
- buf->decoder_info[2] = this->pts > 0 ? 0xffff : 0; /* hack - size unknown here (?) */
-
- this->video_fifo->put (this->video_fifo, buf);
-
- return -1;
-}
-
-int detect_dvb_spu(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf)
-{
- LOGSPU("%s%02x %02x %02x %02x %02x %02x %02x %02x",
- this->pts>0?"* ":" ",p[0], p[1], p[2], p[3],
- p[4], p[5], p[6], p[7]);
-
- /* If PES packet has PTS, it starts new subtitle (ES) packet. */
- if (this->pts > 0) {
- /* Reset SPU type */
- this->subtitle_type = 0;
- }
-
-# ifdef VDR_SUBTITLES
- /* Compatibility mode for old subtitles plugin */
- if (this->subtitle_type != BUF_SPU_DVD) {
- if ((buf->content[7] & 0x01) && (p[-3] & 0x81) == 0x01 && p[-2] == 0x81) {
- LOGDBG("DVB SPU: Old vdr-subtitles compability mode");
- return parse_dvb_spu(this, p, buf, 1);
- }
- }
-# endif /* VDR_SUBTITLES */
-
- /* Start of subtitle packet. Guess substream type */
- if (this->pts > 0) {
- if (p[4] == 0x20 && p[5] == 0x00 && (p[6] == 0x0f || p[4] == 0x0f)) {
- this->subtitle_type = BUF_SPU_DVB;
- LOGSPU(" -> DVB SPU");
- } else if (p[2] || (p[3] & 0xfe)) {
- this->subtitle_type = BUF_SPU_DVD;
- LOGSPU(" -> DVD SPU");
- } else {
- this->subtitle_type = BUF_SPU_DVD;
- LOGMSG(" -> DV? SPU -> DVD");
- }
- }
-
- /* DVD SPU ? */
- if (this->subtitle_type == BUF_SPU_DVD)
- return this->packet_len;
-
- /* DVB SPU */
- return parse_dvb_spu(this, p, buf, 4);
-}
-
-#endif /* TEST_DVB_SPU */
-
-static int32_t parse_private_stream_1(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf)
-{
- int track, spu_id;
- int32_t result;
-
- result = parse_pes_for_pts(this, p, buf);
- if (result < 0) return -1;
-
- p += result;
-
- /* SPU */
- if ((p[0] & 0xE0) == 0x20) {
- spu_id = (p[0] & 0x1f);
-
- if (this->pts <= 0 && !this->subtitle_type) {
- /* need whole ES packet (after seek etc.) */
- buf->free_buffer(buf);
- return -1;
- }
-
-#ifdef TEST_DVB_SPU
- if (detect_dvb_spu(this, p, buf) < 0)
- return -1;
-#endif /* TEST_DVB_SPU */
- this->subtitle_type = BUF_SPU_DVD;
-
- /* DVD SPU */
- buf->content = p+1;
- buf->size = this->packet_len-1;
-
- buf->type = BUF_SPU_DVD + spu_id;
- buf->decoder_flags |= BUF_FLAG_SPECIAL;
- buf->decoder_info[1] = BUF_SPECIAL_SPU_DVD_SUBTYPE;
- buf->decoder_info[2] = SPU_DVD_SUBTYPE_PACKAGE;
- buf->pts = this->pts;
-
- this->video_fifo->put (this->video_fifo, buf);
-
- return -1;
- }
-
- if ((p[0]&0xF0) == 0x80) {
-
- track = p[0] & 0x0F; /* hack : ac3 track */
-
- buf->decoder_info[1] = p[1]; /* Number of frame headers */
- buf->decoder_info[2] = p[2] << 8 | p[3]; /* First access unit pointer */
-
- buf->content = p+4;
- buf->size = this->packet_len-4;
- if (track & 0x8) {
- buf->type = BUF_AUDIO_DTS + (track & 0x07); /* DVDs only have 8 tracks */
- } else {
- buf->type = BUF_AUDIO_A52 + track;
- }
- buf->pts = this->pts;
-
- if (this->audio_fifo) {
- check_newpts( this, buf, PTS_AUDIO );
- track_audio_stream_change (this, buf);
- this->audio_fifo->put (this->audio_fifo, buf);
- return -1;
- } else {
- buf->free_buffer(buf);
- return -1;
- }
-
- } else if ((p[0]&0xf0) == 0xa0) {
-
- int pcm_offset;
- int number_of_frame_headers;
- int first_access_unit_pointer;
- int audio_frame_number;
- int bits_per_sample;
- int sample_rate;
- int num_channels;
- int dynamic_range;
-
- /*
- * found in http://members.freemail.absa.co.za/ginggs/dvd/mpeg2_lpcm.txt
- * appears to be correct.
- */
-
- track = p[0] & 0x0F;
- number_of_frame_headers = p[1];
- /* unknown = p[2]; */
- first_access_unit_pointer = p[3];
- audio_frame_number = p[4];
-
- /*
- * 000 => mono
- * 001 => stereo
- * 010 => 3 channel
- * ...
- * 111 => 8 channel
- */
- num_channels = (p[5] & 0x7) + 1;
- sample_rate = p[5] & 0x10 ? 96000 : 48000;
- switch ((p[5]>>6) & 3) {
- case 3: /* illegal, use 16-bits? */
- default:
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
- "illegal lpcm sample format (%d), assume 16-bit samples\n", (p[5]>>6) & 3 );
- case 0: bits_per_sample = 16; break;
- case 1: bits_per_sample = 20; break;
- case 2: bits_per_sample = 24; break;
- }
- dynamic_range = p[6];
-
- /* send lpcm config byte */
- buf->decoder_flags |= BUF_FLAG_SPECIAL;
- buf->decoder_info[1] = BUF_SPECIAL_LPCM_CONFIG;
- buf->decoder_info[2] = p[5];
-
- pcm_offset = 7;
-
- buf->content = p+pcm_offset;
- buf->size = this->packet_len-pcm_offset;
- buf->type = BUF_AUDIO_LPCM_BE + track;
- buf->pts = this->pts;
-
- if (this->audio_fifo) {
- check_newpts( this, buf, PTS_AUDIO );
- track_audio_stream_change (this, buf);
- this->audio_fifo->put (this->audio_fifo, buf);
- return -1;
- } else {
- buf->free_buffer(buf);
- return -1;
- }
- }
-
- buf->free_buffer(buf);
- return -1;
-}
-
-/*
- * detect_h264()
- *
- * Detect video codec (MPEG2 or H.264)
- */
-static int detect_h264(uint8_t *data)
-{
- /* H.264 detection */
- if (data[0] == 0 && data[1] == 0 && data[2] == 1) {
- if (data[3] == NAL_AUD) {
- LOGMSG("H.264 scanner: Possible H.264 NAL AUD");
- return BUF_VIDEO_H264;
- }
- if (data[3] == 0) {
- LOGDBG("H.264 scanner: Possible MPEG2 start code PICTURE (0x00)");
- return BUF_VIDEO_MPEG;
- }
- if (data[3] >= 0x80) {
- LOGDBG("H.264 scanner: Possible MPEG2 start code (0x%02x)", data[3]);
- return BUF_VIDEO_MPEG;
- }
- LOGMSG("H.264 scanner: Unregonized header 00 00 01 %02x", data[3]);
- }
-
- return 0;
-}
-
-static int32_t parse_video_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf)
-{
- int32_t result;
-
- result = parse_pes_for_pts(this, p, buf);
- if (result < 0) return -1;
-
- p += result;
-
- if (this->video_type == 0) {
- this->video_type = detect_h264(p);
- }
-
- buf->type = this->video_type ?: BUF_VIDEO_MPEG;
- buf->pts = this->pts;
- buf->decoder_info[0] = this->pts - this->dts;
-
- /* MPEG2 */
- if (this->video_type == BUF_VIDEO_MPEG) {
- /* Special handling for FFMPEG MPEG2 decoder */
- if (this->ffmpeg_mpeg2_decoder) {
- uint8_t type = pes_get_picture_type(buf->content, buf->size);
- if (type) {
- /* signal FRAME_END to decoder */
- post_frame_end(this, buf);
- /* for some reason ffmpeg mpeg2 decoder does not understand pts'es in B frames ?
- * (B-frame pts's are smaller than in previous P-frame)
- * Anyway, without this block of code B frames with pts are dropped. */
- if (type == B_FRAME)
- buf->pts = 0;
- }
- }
- }
-
- /* H.264 */
- else if (this->video_type == BUF_VIDEO_H264) {
- /* Access Unit Delimiter */
- if (IS_NAL_AUD(p))
- post_frame_end (this, buf);
-
- /* Check for end of still image.
- VDR ensures that H.264 still images end with an end of sequence NAL unit */
- if (buf->size > 4) {
- uint8_t *end = buf->content + buf->size;
- if (IS_NAL_END_SEQ(end-4)) {
- LOGMSG("post_frame_h264: Still frame ? (frame ends with end of sequence NAL unit)");
- buf->decoder_flags |= BUF_FLAG_FRAME_END;
- }
- }
- }
-
- buf->content = p;
- buf->size = this->packet_len;
-
- check_newpts( this, buf, PTS_VIDEO );
-
- this->video_fifo->put (this->video_fifo, buf);
-
- return -1;
-}
-
-static int32_t parse_audio_stream(demux_xvdr_t *this, uint8_t *p, buf_element_t *buf)
-{
- int track;
- int32_t result;
-
- result = parse_pes_for_pts(this, p, buf);
- if (result < 0) return -1;
-
- p += result;
-
- track = this->stream_id & 0x1f;
-
- buf->content = p;
- buf->size = this->packet_len;
- buf->type = BUF_AUDIO_MPEG + track;
- buf->pts = this->pts;
-
- if (this->audio_fifo) {
- check_newpts( this, buf, PTS_AUDIO );
- track_audio_stream_change (this, buf);
- this->audio_fifo->put (this->audio_fifo, buf);
- } else {
- buf->free_buffer(buf);
- }
-
- return -1;
-}
-
-/*
- * interface
- */
-
-static int demux_xvdr_send_chunk (demux_plugin_t *this_gen)
-{
- demux_xvdr_t *this = (demux_xvdr_t *) this_gen;
-
- demux_xvdr_parse_pack(this);
-
- return this->status;
-}
-
-static void demux_xvdr_dispose (demux_plugin_t *this_gen)
-{
- demux_xvdr_t *this = (demux_xvdr_t *) this_gen;
-
- LOGDBG("demux_xvdr_dispose()");
-
- ts_data_dispose(&this->ts_data);
-
- free (this);
-}
-
-static int demux_xvdr_get_status (demux_plugin_t *this_gen)
-{
- demux_xvdr_t *this = (demux_xvdr_t *) this_gen;
-
- if (this->status != DEMUX_OK) {
- if (this->ts_data) {
- LOGMSG("demux_xvdr_get_status(): status != DEMUX_OK. -> freeing ts_data");
- ts_data_dispose(&this->ts_data);
- }
- }
-
- return this->status;
-}
-
-static void demux_xvdr_send_headers (demux_plugin_t *this_gen)
-{
- demux_xvdr_t *this = (demux_xvdr_t *) this_gen;
-
- this->video_fifo = this->stream->video_fifo;
- this->audio_fifo = this->stream->audio_fifo;
-
- /*
- * send start buffer
- */
-
- _x_demux_control_start(this->stream);
-
- this->status = DEMUX_OK;
-
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, 5000000);
-}
-
-
-static int demux_xvdr_seek (demux_plugin_t *this_gen,
- off_t start_pos, int start_time, int playing)
-{
- demux_xvdr_t *this = (demux_xvdr_t *) this_gen;
-
- /*
- * now start demuxing
- */
- this->send_newpts = 1;
- this->video_type = 0;
- this->audio_type = 0;
- this->subtitle_type = 0;
- this->bih_posted = 0;
- ts_data_dispose(&this->ts_data);
-
- if (!playing) {
-
- this->buf_flag_seek = 0;
- this->status = DEMUX_OK;
- this->last_pts[0] = 0;
- this->last_pts[1] = 0;
- } else {
- this->buf_flag_seek = 1;
- this->last_vpts = INT64_C(-1);
- _x_demux_flush_engine(this->stream);
- }
-
- return this->status;
-}
-
-/*
- * demux class
- */
-
-static int demux_xvdr_get_stream_length (demux_plugin_t *this_gen)
-{
- return 0;
-}
-
-static uint32_t demux_xvdr_get_capabilities(demux_plugin_t *this_gen)
-{
- return DEMUX_CAP_NOCAP;
-}
-
-static int demux_xvdr_get_optional_data(demux_plugin_t *this_gen,
- void *data, int data_type)
-{
- return DEMUX_OPTIONAL_UNSUPPORTED;
-}
-
-static demux_plugin_t *demux_xvdr_open_plugin (demux_class_t *class_gen,
- xine_stream_t *stream,
- input_plugin_t *input_gen)
-{
- input_plugin_t *input = (input_plugin_t *) input_gen;
- demux_xvdr_t *this;
- const char *mrl = input->get_mrl(input);
-
- if (strncmp(mrl, MRL_ID ":/", MRL_ID_LEN + 2 ) &&
- strncmp(mrl, MRL_ID "+pipe://", MRL_ID_LEN + 8) &&
- strncmp(mrl, MRL_ID "+tcp://", MRL_ID_LEN + 7) &&
- strncmp(mrl, MRL_ID "+udp://", MRL_ID_LEN + 7) &&
- strncmp(mrl, MRL_ID "+rtp://", MRL_ID_LEN + 7))
- return NULL;
-
- this = calloc(1, sizeof(demux_xvdr_t));
- this->stream = stream;
- this->input = input;
-
- this->demux_plugin.send_headers = demux_xvdr_send_headers;
- this->demux_plugin.send_chunk = demux_xvdr_send_chunk;
- this->demux_plugin.seek = demux_xvdr_seek;
- this->demux_plugin.dispose = demux_xvdr_dispose;
- this->demux_plugin.get_status = demux_xvdr_get_status;
- this->demux_plugin.get_stream_length = demux_xvdr_get_stream_length;
- this->demux_plugin.get_capabilities = demux_xvdr_get_capabilities;
- this->demux_plugin.get_optional_data = demux_xvdr_get_optional_data;
- this->demux_plugin.demux_class = class_gen;
-
- this->status = DEMUX_FINISHED;
-
- detect_video_decoders(this);
-
- return &this->demux_plugin;
-}
-
-#if DEMUXER_PLUGIN_IFACE_VERSION < 27
-static const char *demux_xvdr_get_description (demux_class_t *this_gen)
-{
- return MRL_ID " demux plugin";
-}
-
-static const char *demux_xvdr_get_identifier (demux_class_t *this_gen)
-{
- return MRL_ID;
-}
-
-static const char *demux_xvdr_get_extensions (demux_class_t *this_gen)
-{
- return NULL;
-}
-
-static const char *demux_xvdr_get_mimetypes (demux_class_t *this_gen)
-{
- return NULL;
-}
-
-static void demux_xvdr_class_dispose (demux_class_t *this_gen)
-{
- demux_xvdr_class_t *this = (demux_xvdr_class_t *) this_gen;
-
- free (this);
-}
-#endif
-
-void *demux_xvdr_init_class (xine_t *xine, void *data)
-{
- demux_xvdr_class_t *this;
-
- this = calloc(1, sizeof(demux_xvdr_class_t));
- this->config = xine->config;
- this->xine = xine;
-
- this->demux_class.open_plugin = demux_xvdr_open_plugin;
-#if DEMUXER_PLUGIN_IFACE_VERSION < 27
- this->demux_class.get_description = demux_xvdr_get_description;
- this->demux_class.get_identifier = demux_xvdr_get_identifier;
- this->demux_class.get_mimetypes = demux_xvdr_get_mimetypes;
- this->demux_class.get_extensions = demux_xvdr_get_extensions;
- this->demux_class.dispose = demux_xvdr_class_dispose;
-#else
- this->demux_class.description = N_("XVDR demux plugin");
- this->demux_class.identifier = MRL_ID;
- this->demux_class.mimetypes = NULL;
- this->demux_class.extensions =
- MRL_ID":/ "
- MRL_ID"+pipe:/ "
- MRL_ID"+tcp:/ "
- MRL_ID"+udp:/ "
- MRL_ID"+rtp:/ "
- MRL_ID"+slave:/";
- this->demux_class.dispose = default_demux_class_dispose;
-#endif
-
- return this;
-}
-
-