diff options
Diffstat (limited to 'gst/mpegvideoparse/mpegpacketiser.c')
-rw-r--r-- | gst/mpegvideoparse/mpegpacketiser.c | 181 |
1 files changed, 178 insertions, 3 deletions
diff --git a/gst/mpegvideoparse/mpegpacketiser.c b/gst/mpegvideoparse/mpegpacketiser.c index 5c054ed8..318805fd 100644 --- a/gst/mpegvideoparse/mpegpacketiser.c +++ b/gst/mpegvideoparse/mpegpacketiser.c @@ -87,7 +87,7 @@ mpeg_packetiser_flush (MPEGPacketiser * p) } guint8 * -mpeg_find_start_code (guint32 * sync_word, guint8 * cur, guint8 * end) +mpeg_util_find_start_code (guint32 * sync_word, guint8 * cur, guint8 * end) { guint32 code = *sync_word; @@ -351,7 +351,7 @@ collect_packets (MPEGPacketiser * p, GstBuffer * buf) guint8 *cur; guint8 *end = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf); - cur = mpeg_find_start_code (&(p->sync_word), GST_BUFFER_DATA (buf), end); + cur = mpeg_util_find_start_code (&(p->sync_word), GST_BUFFER_DATA (buf), end); while (cur != NULL) { /* Calculate the offset as tracked since the last flush. Note that cur * points to the last byte of the sync word, so we adjust by -3 to get the @@ -359,7 +359,7 @@ collect_packets (MPEGPacketiser * p, GstBuffer * buf) guint64 offset = p->tracked_offset + (cur - GST_BUFFER_DATA (buf) - 3); handle_packet (p, offset, *cur); - cur = mpeg_find_start_code (&(p->sync_word), cur, end); + cur = mpeg_util_find_start_code (&(p->sync_word), cur, end); } } @@ -436,3 +436,178 @@ mpeg_packetiser_next_block (MPEGPacketiser * p) else p->first_block_idx = next; } + +/* Set the Pixel Aspect Ratio in our hdr from a DAR code in the data */ +static void +set_par_from_dar (MPEGSeqHdr * hdr, guint8 asr_code) +{ + /* Pixel_width = DAR_width * display_vertical_size */ + /* Pixel_height = DAR_height * display_horizontal_size */ + switch (asr_code) { + case 0x02: /* 3:4 DAR = 4:3 pixels */ + hdr->par_w = 4 * hdr->height; + hdr->par_h = 3 * hdr->width; + break; + case 0x03: /* 9:16 DAR */ + hdr->par_w = 16 * hdr->height; + hdr->par_h = 9 * hdr->width; + break; + case 0x04: /* 1:2.21 DAR */ + hdr->par_w = 221 * hdr->height; + hdr->par_h = 100 * hdr->width; + break; + case 0x01: /* Square pixels */ + default: + hdr->par_w = hdr->par_h = 1; + break; + } +} + +static void +set_fps_from_code (MPEGSeqHdr * hdr, guint8 fps_code) +{ + const gint framerates[][2] = { + {30, 1}, {24000, 1001}, {24, 1}, {25, 1}, + {30000, 1001}, {30, 1}, {50, 1}, {60000, 1001}, + {60, 1}, {30, 1} + }; + + if (fps_code < 10) { + hdr->fps_n = framerates[fps_code][0]; + hdr->fps_d = framerates[fps_code][1]; + } else { + /* Force a valid framerate */ + hdr->fps_n = 30000; + hdr->fps_d = 1001; + } +} + +static gboolean +mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) +{ + guint8 ext_code; + + if (G_UNLIKELY ((end - data - 1) < 1)) + return FALSE; /* short extension packet */ + + ext_code = data[0] >> 4; + + switch (ext_code) { + case MPEG_PACKET_EXT_SEQUENCE: + { + /* Parse a Sequence Extension */ + guint8 horiz_size_ext, vert_size_ext; + guint8 fps_n_ext, fps_d_ext; + + if ((end - data - 1) < 6) + /* need at least 10 bytes, minus 4 for the start code 000001b5 */ + return FALSE; + + horiz_size_ext = ((data[1] << 1) & 0x02) | ((data[2] >> 7) & 0x01); + vert_size_ext = (data[2] >> 5) & 0x03; + fps_n_ext = (data[5] >> 5) & 0x03; + fps_d_ext = data[5] & 0x1f; + + hdr->fps_n *= (fps_n_ext + 1); + hdr->fps_d *= (fps_d_ext + 1); + hdr->width += (horiz_size_ext << 12); + hdr->height += (vert_size_ext << 12); + break; + } + default: + break; + } + + return TRUE; +} + +gboolean +mpeg_util_parse_sequence_hdr (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) +{ + guint32 code; + guint8 dar_idx, fps_idx; + guint32 sync_word = 0xffffffff; + gboolean constrained_flag; + gboolean load_intra_flag; + gboolean load_non_intra_flag; + + if (G_UNLIKELY ((end - data - 1) < 12)) + return FALSE; /* Too small to be a sequence header */ + + code = GST_READ_UINT32_BE (data); + if (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_SEQUENCE))) + return FALSE; + + /* Skip the sync word */ + data += 4; + + /* Parse the MPEG 1 bits */ + hdr->mpeg_version = 1; + + code = GST_READ_UINT32_BE (data); + hdr->width = (code >> 20) & 0xfff; + hdr->height = (code >> 8) & 0xfff; + + dar_idx = (code >> 4) & 0xf; + set_par_from_dar (hdr, dar_idx); + fps_idx = code & 0xf; + set_fps_from_code (hdr, fps_idx); + + constrained_flag = (data[7] >> 2) & 0x01; + load_intra_flag = (data[7] >> 1) & 0x01; + if (load_intra_flag) { + if (G_UNLIKELY ((end - data - 1) < 64)) + return FALSE; + data += 64; + } + + load_non_intra_flag = data[7] & 0x01; + if (load_non_intra_flag) { + if (G_UNLIKELY ((end - data - 1) < 64)) + return FALSE; + data += 64; + } + + /* Advance past the rest of the MPEG-1 header */ + data += 8; + + /* Read MPEG-2 sequence extensions */ + data = mpeg_util_find_start_code (&sync_word, data, end); + while (data != NULL) { + if (G_UNLIKELY ((end - data - 1) < 1)) + return FALSE; + + /* data points at the last byte of the start code */ + if (data[0] == MPEG_PACKET_EXTENSION) { + if (!mpeg_util_parse_extension_packet (hdr, data + 1, end)) + return FALSE; + + hdr->mpeg_version = 2; + } + data = mpeg_util_find_start_code (&sync_word, data, end); + } + + return TRUE; +} + +gboolean +mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end) +{ + guint32 code; + + if (G_UNLIKELY ((end - data - 1) < 6)) + return FALSE; /* Packet too small */ + + code = GST_READ_UINT32_BE (data); + if (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_PICTURE))) + return FALSE; + + /* Skip the start code */ + data += 4; + + hdr->pic_type = (data[1] >> 3) & 0x07; + if (hdr->pic_type == 0 || hdr->pic_type > 4) + return FALSE; /* Corrupted picture packet */ + + return TRUE; +} |