The two types of packets (PCI and DSI) are passed untouched but combined by the new codec ID AV_CODEC_ID_DVD_NAV. The first 980 bytes in the packet contain the PCI data. The next 1018 are the DSI data. Signed-off-by: Michael Niedermayer <michaelni@gmx.at>tags/n2.0
| @@ -743,6 +743,7 @@ OBJS-$(CONFIG_PNG_PARSER) += png_parser.o | |||
| OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o \ | |||
| mpegaudiodecheader.o mpegaudiodata.o | |||
| OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ | |||
| dvd_nav_parser.o \ | |||
| mpeg12.o mpeg12data.o | |||
| OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o | |||
| OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o | |||
| @@ -515,6 +515,7 @@ void avcodec_register_all(void) | |||
| REGISTER_PARSER(DNXHD, dnxhd); | |||
| REGISTER_PARSER(DVBSUB, dvbsub); | |||
| REGISTER_PARSER(DVDSUB, dvdsub); | |||
| REGISTER_PARSER(DVD_NAV, dvd_nav); | |||
| REGISTER_PARSER(FLAC, flac); | |||
| REGISTER_PARSER(GSM, gsm); | |||
| REGISTER_PARSER(H261, h261); | |||
| @@ -482,6 +482,8 @@ enum AVCodecID { | |||
| AV_CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'), | |||
| AV_CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'), | |||
| AV_CODEC_ID_SMPTE_KLV = MKBETAG('K','L','V','A'), | |||
| AV_CODEC_ID_DVD_NAV = MKBETAG('D','N','A','V'), | |||
| AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it | |||
| @@ -2525,6 +2525,12 @@ static const AVCodecDescriptor codec_descriptors[] = { | |||
| .name = "klv", | |||
| .long_name = NULL_IF_CONFIG_SMALL("SMPTE 336M Key-Length-Value (KLV) metadata"), | |||
| }, | |||
| { | |||
| .id = AV_CODEC_ID_DVD_NAV, | |||
| .type = AVMEDIA_TYPE_DATA, | |||
| .name = "dvd_nav_packet", | |||
| .long_name = NULL_IF_CONFIG_SMALL("DVD Nav packet"), | |||
| }, | |||
| }; | |||
| @@ -0,0 +1,116 @@ | |||
| /* | |||
| * DVD navigation block parser for FFmpeg | |||
| * Copyright (c) 2013 The FFmpeg Project | |||
| * | |||
| * This file is part of FFmpeg. | |||
| * | |||
| * FFmpeg is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 2.1 of the License, or (at your option) any later version. | |||
| * | |||
| * FFmpeg 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 | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with FFmpeg; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include "avcodec.h" | |||
| #include "dsputil.h" | |||
| #include "get_bits.h" | |||
| #include "parser.h" | |||
| #define PCI_SIZE 980 | |||
| #define DSI_SIZE 1018 | |||
| /* parser definition */ | |||
| typedef struct DVDNavParseContext { | |||
| uint32_t lba; | |||
| uint8_t buffer[PCI_SIZE+DSI_SIZE]; | |||
| int copied; | |||
| } DVDNavParseContext; | |||
| static av_cold int dvd_nav_parse_init(AVCodecParserContext *s) | |||
| { | |||
| DVDNavParseContext *pc = s->priv_data; | |||
| pc->lba = 0xFFFFFFFF; | |||
| pc->copied = 0; | |||
| return 0; | |||
| } | |||
| static int dvd_nav_parse(AVCodecParserContext *s, | |||
| AVCodecContext *avctx, | |||
| const uint8_t **poutbuf, int *poutbuf_size, | |||
| const uint8_t *buf, int buf_size) | |||
| { | |||
| DVDNavParseContext *pc1 = s->priv_data; | |||
| int lastPacket = 0; | |||
| int valid = 0; | |||
| s->pict_type = AV_PICTURE_TYPE_NONE; | |||
| avctx->time_base.num = 1; | |||
| avctx->time_base.den = 90000; | |||
| if (buf && buf_size) { | |||
| switch(buf[0]) { | |||
| case 0x00: | |||
| if (buf_size == PCI_SIZE) { | |||
| /* PCI */ | |||
| uint32_t lba = AV_RB32(&buf[0x01]); | |||
| uint32_t startpts = AV_RB32(&buf[0x0D]); | |||
| uint32_t endpts = AV_RB32(&buf[0x11]); | |||
| if (endpts > startpts) { | |||
| pc1->lba = lba; | |||
| s->pts = (int64_t)startpts; | |||
| s->duration = endpts - startpts; | |||
| memcpy(pc1->buffer, buf, PCI_SIZE); | |||
| pc1->copied = PCI_SIZE; | |||
| valid = 1; | |||
| } | |||
| } | |||
| break; | |||
| case 0x01: | |||
| if ((buf_size == DSI_SIZE) && (pc1->copied == PCI_SIZE)) { | |||
| /* DSI */ | |||
| uint32_t lba = AV_RB32(&buf[0x05]); | |||
| if (lba == pc1->lba) { | |||
| memcpy(pc1->buffer + pc1->copied, buf, DSI_SIZE); | |||
| lastPacket = 1; | |||
| valid = 1; | |||
| } | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| if (!valid || lastPacket) { | |||
| pc1->copied = 0; | |||
| pc1->lba = 0xFFFFFFFF; | |||
| } | |||
| if (lastPacket) { | |||
| *poutbuf = pc1->buffer; | |||
| *poutbuf_size = sizeof(pc1->buffer); | |||
| } else { | |||
| *poutbuf = NULL; | |||
| *poutbuf_size = 0; | |||
| } | |||
| return buf_size; | |||
| } | |||
| AVCodecParser ff_dvd_nav_parser = { | |||
| .codec_ids = { AV_CODEC_ID_DVD_NAV }, | |||
| .priv_data_size = sizeof(DVDNavParseContext), | |||
| .parser_init = dvd_nav_parse_init, | |||
| .parser_parse = dvd_nav_parse, | |||
| }; | |||
| @@ -29,7 +29,7 @@ | |||
| #include "libavutil/avutil.h" | |||
| #define LIBAVCODEC_VERSION_MAJOR 55 | |||
| #define LIBAVCODEC_VERSION_MINOR 0 | |||
| #define LIBAVCODEC_VERSION_MINOR 1 | |||
| #define LIBAVCODEC_VERSION_MICRO 100 | |||
| #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | |||
| @@ -30,6 +30,7 @@ | |||
| #undef NDEBUG | |||
| #include <assert.h> | |||
| #include "libavutil/avassert.h" | |||
| /*********************************************/ | |||
| /* demux code */ | |||
| @@ -108,6 +109,7 @@ typedef struct MpegDemuxContext { | |||
| int32_t header_state; | |||
| unsigned char psm_es_type[256]; | |||
| int sofdec; | |||
| int dvd; | |||
| #if CONFIG_VOBSUB_DEMUXER | |||
| AVFormatContext *sub_ctx; | |||
| FFDemuxSubtitlesQueue q; | |||
| @@ -247,21 +249,82 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||
| goto redo; | |||
| } | |||
| if (startcode == PRIVATE_STREAM_2) { | |||
| len = avio_rb16(s->pb); | |||
| if (!m->sofdec) { | |||
| while (len-- >= 6) { | |||
| if (avio_r8(s->pb) == 'S') { | |||
| uint8_t buf[5]; | |||
| avio_read(s->pb, buf, sizeof(buf)); | |||
| m->sofdec = !memcmp(buf, "ofdec", 5); | |||
| len -= sizeof(buf); | |||
| break; | |||
| /* Need to detect whether this from a DVD or a 'Sofdec' stream */ | |||
| int len = avio_rb16(s->pb); | |||
| int bytesread = 0; | |||
| uint8_t *ps2buf = av_malloc(len); | |||
| if (ps2buf) { | |||
| bytesread = avio_read(s->pb, ps2buf, len); | |||
| if (bytesread != len) { | |||
| avio_skip(s->pb, len - bytesread); | |||
| } else { | |||
| uint8_t *p = 0; | |||
| if (len >= 6) | |||
| p = memchr(ps2buf, 'S', len - 5); | |||
| if (p) | |||
| m->sofdec = !memcmp(p+1, "ofdec", 5); | |||
| m->sofdec -= !m->sofdec; | |||
| if (m->sofdec < 0) { | |||
| if (len == 980 && ps2buf[0] == 0) { | |||
| /* PCI structure? */ | |||
| uint32_t startpts = AV_RB32(ps2buf + 0x0d); | |||
| uint32_t endpts = AV_RB32(ps2buf + 0x11); | |||
| uint8_t hours = ((ps2buf[0x19] >> 4) * 10) + (ps2buf[0x19] & 0x0f); | |||
| uint8_t mins = ((ps2buf[0x1a] >> 4) * 10) + (ps2buf[0x1a] & 0x0f); | |||
| uint8_t secs = ((ps2buf[0x1b] >> 4) * 10) + (ps2buf[0x1b] & 0x0f); | |||
| m->dvd = (hours <= 23 && | |||
| mins <= 59 && | |||
| secs <= 59 && | |||
| (ps2buf[0x19] & 0x0f) < 10 && | |||
| (ps2buf[0x1a] & 0x0f) < 10 && | |||
| (ps2buf[0x1b] & 0x0f) < 10 && | |||
| endpts >= startpts); | |||
| } else if (len == 1018 && ps2buf[0] == 1) { | |||
| /* DSI structure? */ | |||
| uint8_t hours = ((ps2buf[0x1d] >> 4) * 10) + (ps2buf[0x1d] & 0x0f); | |||
| uint8_t mins = ((ps2buf[0x1e] >> 4) * 10) + (ps2buf[0x1e] & 0x0f); | |||
| uint8_t secs = ((ps2buf[0x1f] >> 4) * 10) + (ps2buf[0x1f] & 0x0f); | |||
| m->dvd = (hours <= 23 && | |||
| mins <= 59 && | |||
| secs <= 59 && | |||
| (ps2buf[0x1d] & 0x0f) < 10 && | |||
| (ps2buf[0x1e] & 0x0f) < 10 && | |||
| (ps2buf[0x1f] & 0x0f) < 10); | |||
| } | |||
| } | |||
| } | |||
| av_free(ps2buf); | |||
| /* If this isn't a DVD packet or no memory | |||
| * could be allocated, just ignore it. | |||
| * If we did, move back to the start of the | |||
| * packet (plus 'length' field) */ | |||
| if (!m->dvd || avio_skip(s->pb, -(len + 2)) < 0) { | |||
| /* Skip back failed. | |||
| * This packet will be lost but that can't be helped | |||
| * if we can't skip back | |||
| */ | |||
| goto redo; | |||
| } | |||
| } else { | |||
| /* No memory */ | |||
| avio_skip(s->pb, len); | |||
| goto redo; | |||
| } | |||
| m->sofdec -= !m->sofdec; | |||
| } else if (!m->dvd) { | |||
| int len = avio_rb16(s->pb); | |||
| avio_skip(s->pb, len); | |||
| goto redo; | |||
| } | |||
| avio_skip(s->pb, len); | |||
| goto redo; | |||
| } | |||
| if (startcode == PROGRAM_STREAM_MAP) { | |||
| mpegps_psm_parse(m, s->pb); | |||
| @@ -271,7 +334,9 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||
| /* find matching stream */ | |||
| if (!((startcode >= 0x1c0 && startcode <= 0x1df) || | |||
| (startcode >= 0x1e0 && startcode <= 0x1ef) || | |||
| (startcode == 0x1bd) || (startcode == 0x1fd))) | |||
| (startcode == 0x1bd) || | |||
| (startcode == PRIVATE_STREAM_2) || | |||
| (startcode == 0x1fd))) | |||
| goto redo; | |||
| if (ppos) { | |||
| *ppos = avio_tell(s->pb) - 4; | |||
| @@ -279,6 +344,8 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||
| len = avio_rb16(s->pb); | |||
| pts = | |||
| dts = AV_NOPTS_VALUE; | |||
| if (startcode != PRIVATE_STREAM_2) | |||
| { | |||
| /* stuffing */ | |||
| for(;;) { | |||
| if (len < 1) | |||
| @@ -352,6 +419,7 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||
| } | |||
| else if( c!= 0xf ) | |||
| goto redo; | |||
| } | |||
| if (startcode == PRIVATE_STREAM_1) { | |||
| startcode = avio_r8(s->pb); | |||
| @@ -448,6 +516,9 @@ static int mpegps_read_packet(AVFormatContext *s, | |||
| else | |||
| request_probe= 1; | |||
| type = AVMEDIA_TYPE_VIDEO; | |||
| } else if (startcode == PRIVATE_STREAM_2) { | |||
| type = AVMEDIA_TYPE_DATA; | |||
| codec_id = AV_CODEC_ID_DVD_NAV; | |||
| } else if (startcode >= 0x1c0 && startcode <= 0x1df) { | |||
| type = AVMEDIA_TYPE_AUDIO; | |||
| codec_id = m->sofdec > 0 ? AV_CODEC_ID_ADPCM_ADX : AV_CODEC_ID_MP2; | |||