summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libmpeg2/decode.c155
-rw-r--r--src/libmpeg2/mpeg2.h6
2 files changed, 125 insertions, 36 deletions
diff --git a/src/libmpeg2/decode.c b/src/libmpeg2/decode.c
index a2bb868df..2b2426950 100644
--- a/src/libmpeg2/decode.c
+++ b/src/libmpeg2/decode.c
@@ -87,6 +87,10 @@ void mpeg2_init (mpeg2dec_t * mpeg2dec,
mpeg2dec->code = 0xb4;
mpeg2dec->seek_mode = 0;
+ /* initialize AFD storage */
+ mpeg2dec->afd_value_seen = XINE_VIDEO_AFD_NOT_PRESENT;
+ mpeg2dec->afd_value_reported = (XINE_VIDEO_AFD_NOT_PRESENT - 1);
+
memset (mpeg2dec->picture, 0, sizeof (picture_t));
/* initialize substructures */
@@ -236,7 +240,7 @@ static void remember_metainfo (mpeg2dec_t *mpeg2dec) {
}
static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code,
- uint8_t * buffer)
+ uint8_t * buffer, int next_code)
{
picture_t * picture;
int is_frame_done;
@@ -393,6 +397,14 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code,
/* abort(); */
break;
}
+
+ /* reset AFD value to detect absence */
+ mpeg2dec->afd_value_seen = XINE_VIDEO_AFD_NOT_PRESENT;
+
+ /* according to ISO/IEC 13818-2, an extension start code will follow.
+ * Otherwise the stream follows ISO/IEC 11172-2 which means MPEG1 */
+ picture->mpeg1 = (next_code != 0xb5);
+
if (mpeg2dec->force_aspect) picture->aspect_ratio_information = mpeg2dec->force_aspect;
if (mpeg2dec->is_sequence_needed ) {
@@ -464,6 +476,18 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code,
if (code >= 0xb0)
break;
+ /* check for AFD change once per picture */
+ if (mpeg2dec->afd_value_reported != mpeg2dec->afd_value_seen) {
+ /* AFD data should better be stored in current_frame to have it */
+ /* ready and synchronous with other data like width or height. */
+ /* An AFD change should then be detected when a new frame is emitted */
+ /* from the decoder to report the AFD change in display order and not */
+ /* in decoding order like it happens below for now. */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_AFD, mpeg2dec->afd_value_seen);
+fprintf(stderr, "AFD changed from %d to %d\n", mpeg2dec->afd_value_reported, mpeg2dec->afd_value_seen);
+ mpeg2dec->afd_value_reported = mpeg2dec->afd_value_seen;
+ }
+
if (!(mpeg2dec->in_slice)) {
mpeg2dec->in_slice = 1;
@@ -574,45 +598,102 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code,
return is_frame_done;
}
+static inline int find_start_code (mpeg2dec_t * mpeg2dec,
+ uint8_t ** current, uint8_t * limit)
+{
+ uint8_t * p;
+
+ if (*current >= limit)
+ return 0;
+ if (mpeg2dec->shift == 0x00000100)
+ return 1;
+
+ mpeg2dec->shift = (mpeg2dec->shift | *(*current)++) << 8;
+
+ if (*current >= limit)
+ return 0;
+ if (mpeg2dec->shift == 0x00000100)
+ return 1;
+
+ mpeg2dec->shift = (mpeg2dec->shift | *(*current)++) << 8;
+
+ if (*current >= limit)
+ return 0;
+ if (mpeg2dec->shift == 0x00000100)
+ return 1;
+
+ limit--;
+
+ if (*current >= limit) {
+ mpeg2dec->shift = (mpeg2dec->shift | *(*current)++) << 8;
+ return 0;
+ }
+
+ p = *current;
+
+ while (p < limit && (p = (uint8_t *)memchr(p, 0x01, limit - p))) {
+ if (p[-2] || p[-1])
+ p += 3;
+ else {
+ *current = ++p;
+ return 1;
+ }
+ }
+
+ *current = ++limit;
+ p = limit - 3;
+ mpeg2dec->shift = (mpeg2dec->shift | *p++) << 8;
+ mpeg2dec->shift = (mpeg2dec->shift | *p++) << 8;
+ mpeg2dec->shift = (mpeg2dec->shift | *p++) << 8;
+
+ return 0;
+}
+
static inline uint8_t * copy_chunk (mpeg2dec_t * mpeg2dec,
uint8_t * current, uint8_t * end)
{
- uint32_t shift;
- uint8_t * chunk_ptr;
uint8_t * limit;
- uint8_t byte;
+ uint8_t * data = current;
+ int found, bite;
+
+ /* sequence end code 0xb7 doesn't have any data and there might be the case
+ * that no start code will follow this code for quite some time (e. g. in case
+ * of a still image.
+ * Therefore, return immediately with a chunk_size of 0. Setting code to 0xb4
+ * will eat up any trailing garbage next time.
+ */
+ if (mpeg2dec->code == 0xb7) {
+ mpeg2dec->code = 0xb4;
+ mpeg2dec->chunk_size = 0;
+ return current;
+ }
- shift = mpeg2dec->shift;
- chunk_ptr = mpeg2dec->chunk_ptr;
- limit = current + (mpeg2dec->chunk_buffer + BUFFER_SIZE - chunk_ptr);
+ limit = current + (mpeg2dec->chunk_buffer + BUFFER_SIZE - mpeg2dec->chunk_ptr);
if (limit > end)
limit = end;
- while (1) {
-
- byte = *current++;
- if (shift != 0x00000100) {
- shift = (shift | byte) << 8;
- *chunk_ptr++ = byte;
- if (current < limit)
- continue;
- if (current == end) {
- mpeg2dec->chunk_ptr = chunk_ptr;
- mpeg2dec->shift = shift;
- return NULL;
- } else {
- /* we filled the chunk buffer without finding a start code */
- mpeg2dec->code = 0xb4; /* sequence_error_code */
- mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
- return current;
- }
- }
- mpeg2dec->code = byte;
- mpeg2dec->chunk_size = chunk_ptr - mpeg2dec->chunk_buffer - 3;
+ found = find_start_code(mpeg2dec, &current, limit);
+ bite = current - data;
+ if (bite) {
+ xine_fast_memcpy(mpeg2dec->chunk_ptr, data, bite);
+ mpeg2dec->chunk_ptr += bite;
+ }
+
+ if (found) {
+ mpeg2dec->code = *current++;
+ mpeg2dec->chunk_size = mpeg2dec->chunk_ptr - mpeg2dec->chunk_buffer - 3;
mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
mpeg2dec->shift = 0xffffff00;
return current;
}
+
+ if (current == end)
+ return NULL;
+
+ /* we filled the chunk buffer without finding a start code */
+ mpeg2dec->code = 0xb4; /* sequence_error_code */
+ mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
+ return current;
}
int mpeg2_decode_data (mpeg2dec_t * mpeg2dec, uint8_t * current, uint8_t * end,
@@ -633,12 +714,12 @@ int mpeg2_decode_data (mpeg2dec_t * mpeg2dec, uint8_t * current, uint8_t * end,
if (pts)
mpeg2dec->pts = pts;
- while (current != end) {
+ while (current != end || mpeg2dec->code == 0xb7) {
code = mpeg2dec->code;
current = copy_chunk (mpeg2dec, current, end);
if (current == NULL)
break;
- ret += parse_chunk (mpeg2dec, code, mpeg2dec->chunk_buffer);
+ ret += parse_chunk (mpeg2dec, code, mpeg2dec->chunk_buffer, mpeg2dec->code);
}
libmpeg2_accel_frame_completion(&mpeg2dec->accel, mpeg2dec->frame_format,
@@ -805,7 +886,7 @@ void mpeg2_close (mpeg2dec_t * mpeg2dec)
void mpeg2_find_sequence_header (mpeg2dec_t * mpeg2dec,
uint8_t * current, uint8_t * end){
- uint8_t code;
+ uint8_t code, next_code;
picture_t *picture = mpeg2dec->picture;
mpeg2dec->seek_mode = 1;
@@ -815,6 +896,7 @@ void mpeg2_find_sequence_header (mpeg2dec_t * mpeg2dec,
current = copy_chunk (mpeg2dec, current, end);
if (current == NULL)
return ;
+ next_code = mpeg2dec->code;
/* printf ("looking for sequence header... %02x\n", code); */
@@ -825,6 +907,11 @@ void mpeg2_find_sequence_header (mpeg2dec_t * mpeg2dec,
printf ("libmpeg2: bad sequence header\n");
continue;
}
+
+ /* according to ISO/IEC 13818-2, an extension start code will follow.
+ * Otherwise the stream follows ISO/IEC 11172-2 which means MPEG1 */
+ picture->mpeg1 = (next_code != 0xb5);
+
if (mpeg2dec->force_aspect) picture->aspect_ratio_information = mpeg2dec->force_aspect;
if (mpeg2dec->is_sequence_needed) {
@@ -918,9 +1005,5 @@ static void process_userdata(mpeg2dec_t *mpeg2dec, uint8_t *buffer)
}
/* check Active Format Description ETSI TS 101 154 V1.5.1 */
else if (buffer[0] == 0x44 && buffer[1] == 0x54 && buffer[2] == 0x47 && buffer[3] == 0x31)
- {
- int afd = (buffer[4] & 0x40) ? (buffer[5] & 0x0f) : -1;
- _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_AFD, afd);
-
- }
+ mpeg2dec->afd_value_seen = (buffer[4] & 0x40) ? (buffer[5] & 0x0f) : XINE_VIDEO_AFD_NOT_PRESENT;
}
diff --git a/src/libmpeg2/mpeg2.h b/src/libmpeg2/mpeg2.h
index 788fa823c..253f300a2 100644
--- a/src/libmpeg2/mpeg2.h
+++ b/src/libmpeg2/mpeg2.h
@@ -57,6 +57,12 @@ typedef struct mpeg2dec_s {
int force_aspect;
int force_pan_scan;
+ /* AFD data can be found after a sequence, group or picture start code */
+ /* and will be stored in afd_value_seen. Later it will be transfered to */
+ /* a stream property and stored into afd_value_reported to detect changes */
+ int afd_value_seen;
+ int afd_value_reported;
+
xine_stream_t *stream;
/* a spu decoder for possible closed captions */