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 \ | OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o \ | ||||
| mpegaudiodecheader.o mpegaudiodata.o | mpegaudiodecheader.o mpegaudiodata.o | ||||
| OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ | OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ | ||||
| dvd_nav_parser.o \ | |||||
| mpeg12.o mpeg12data.o | mpeg12.o mpeg12data.o | ||||
| OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o | OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o | ||||
| OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o | OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o | ||||
| @@ -515,6 +515,7 @@ void avcodec_register_all(void) | |||||
| REGISTER_PARSER(DNXHD, dnxhd); | REGISTER_PARSER(DNXHD, dnxhd); | ||||
| REGISTER_PARSER(DVBSUB, dvbsub); | REGISTER_PARSER(DVBSUB, dvbsub); | ||||
| REGISTER_PARSER(DVDSUB, dvdsub); | REGISTER_PARSER(DVDSUB, dvdsub); | ||||
| REGISTER_PARSER(DVD_NAV, dvd_nav); | |||||
| REGISTER_PARSER(FLAC, flac); | REGISTER_PARSER(FLAC, flac); | ||||
| REGISTER_PARSER(GSM, gsm); | REGISTER_PARSER(GSM, gsm); | ||||
| REGISTER_PARSER(H261, h261); | REGISTER_PARSER(H261, h261); | ||||
| @@ -482,6 +482,8 @@ enum AVCodecID { | |||||
| AV_CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'), | AV_CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'), | ||||
| AV_CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'), | AV_CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'), | ||||
| AV_CODEC_ID_SMPTE_KLV = MKBETAG('K','L','V','A'), | 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 | 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", | .name = "klv", | ||||
| .long_name = NULL_IF_CONFIG_SMALL("SMPTE 336M Key-Length-Value (KLV) metadata"), | .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" | #include "libavutil/avutil.h" | ||||
| #define LIBAVCODEC_VERSION_MAJOR 55 | #define LIBAVCODEC_VERSION_MAJOR 55 | ||||
| #define LIBAVCODEC_VERSION_MINOR 0 | |||||
| #define LIBAVCODEC_VERSION_MINOR 1 | |||||
| #define LIBAVCODEC_VERSION_MICRO 100 | #define LIBAVCODEC_VERSION_MICRO 100 | ||||
| #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | ||||
| @@ -30,6 +30,7 @@ | |||||
| #undef NDEBUG | #undef NDEBUG | ||||
| #include <assert.h> | #include <assert.h> | ||||
| #include "libavutil/avassert.h" | |||||
| /*********************************************/ | /*********************************************/ | ||||
| /* demux code */ | /* demux code */ | ||||
| @@ -108,6 +109,7 @@ typedef struct MpegDemuxContext { | |||||
| int32_t header_state; | int32_t header_state; | ||||
| unsigned char psm_es_type[256]; | unsigned char psm_es_type[256]; | ||||
| int sofdec; | int sofdec; | ||||
| int dvd; | |||||
| #if CONFIG_VOBSUB_DEMUXER | #if CONFIG_VOBSUB_DEMUXER | ||||
| AVFormatContext *sub_ctx; | AVFormatContext *sub_ctx; | ||||
| FFDemuxSubtitlesQueue q; | FFDemuxSubtitlesQueue q; | ||||
| @@ -247,21 +249,82 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||||
| goto redo; | goto redo; | ||||
| } | } | ||||
| if (startcode == PRIVATE_STREAM_2) { | if (startcode == PRIVATE_STREAM_2) { | ||||
| len = avio_rb16(s->pb); | |||||
| if (!m->sofdec) { | 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) { | if (startcode == PROGRAM_STREAM_MAP) { | ||||
| mpegps_psm_parse(m, s->pb); | mpegps_psm_parse(m, s->pb); | ||||
| @@ -271,7 +334,9 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||||
| /* find matching stream */ | /* find matching stream */ | ||||
| if (!((startcode >= 0x1c0 && startcode <= 0x1df) || | if (!((startcode >= 0x1c0 && startcode <= 0x1df) || | ||||
| (startcode >= 0x1e0 && startcode <= 0x1ef) || | (startcode >= 0x1e0 && startcode <= 0x1ef) || | ||||
| (startcode == 0x1bd) || (startcode == 0x1fd))) | |||||
| (startcode == 0x1bd) || | |||||
| (startcode == PRIVATE_STREAM_2) || | |||||
| (startcode == 0x1fd))) | |||||
| goto redo; | goto redo; | ||||
| if (ppos) { | if (ppos) { | ||||
| *ppos = avio_tell(s->pb) - 4; | *ppos = avio_tell(s->pb) - 4; | ||||
| @@ -279,6 +344,8 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||||
| len = avio_rb16(s->pb); | len = avio_rb16(s->pb); | ||||
| pts = | pts = | ||||
| dts = AV_NOPTS_VALUE; | dts = AV_NOPTS_VALUE; | ||||
| if (startcode != PRIVATE_STREAM_2) | |||||
| { | |||||
| /* stuffing */ | /* stuffing */ | ||||
| for(;;) { | for(;;) { | ||||
| if (len < 1) | if (len < 1) | ||||
| @@ -352,6 +419,7 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||||
| } | } | ||||
| else if( c!= 0xf ) | else if( c!= 0xf ) | ||||
| goto redo; | goto redo; | ||||
| } | |||||
| if (startcode == PRIVATE_STREAM_1) { | if (startcode == PRIVATE_STREAM_1) { | ||||
| startcode = avio_r8(s->pb); | startcode = avio_r8(s->pb); | ||||
| @@ -448,6 +516,9 @@ static int mpegps_read_packet(AVFormatContext *s, | |||||
| else | else | ||||
| request_probe= 1; | request_probe= 1; | ||||
| type = AVMEDIA_TYPE_VIDEO; | 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) { | } else if (startcode >= 0x1c0 && startcode <= 0x1df) { | ||||
| type = AVMEDIA_TYPE_AUDIO; | type = AVMEDIA_TYPE_AUDIO; | ||||
| codec_id = m->sofdec > 0 ? AV_CODEC_ID_ADPCM_ADX : AV_CODEC_ID_MP2; | codec_id = m->sofdec > 0 ? AV_CODEC_ID_ADPCM_ADX : AV_CODEC_ID_MP2; | ||||