yading@10: /* yading@10: * DVD navigation block parser for FFmpeg yading@10: * Copyright (c) 2013 The FFmpeg Project yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: #include "avcodec.h" yading@10: #include "dsputil.h" yading@10: #include "get_bits.h" yading@10: #include "parser.h" yading@10: yading@10: #define PCI_SIZE 980 yading@10: #define DSI_SIZE 1018 yading@10: yading@10: /* parser definition */ yading@10: typedef struct DVDNavParseContext { yading@10: uint32_t lba; yading@10: uint8_t buffer[PCI_SIZE+DSI_SIZE]; yading@10: int copied; yading@10: } DVDNavParseContext; yading@10: yading@10: static av_cold int dvd_nav_parse_init(AVCodecParserContext *s) yading@10: { yading@10: DVDNavParseContext *pc = s->priv_data; yading@10: yading@10: pc->lba = 0xFFFFFFFF; yading@10: pc->copied = 0; yading@10: return 0; yading@10: } yading@10: yading@10: static int dvd_nav_parse(AVCodecParserContext *s, yading@10: AVCodecContext *avctx, yading@10: const uint8_t **poutbuf, int *poutbuf_size, yading@10: const uint8_t *buf, int buf_size) yading@10: { yading@10: DVDNavParseContext *pc1 = s->priv_data; yading@10: int lastPacket = 0; yading@10: int valid = 0; yading@10: yading@10: s->pict_type = AV_PICTURE_TYPE_NONE; yading@10: yading@10: avctx->time_base.num = 1; yading@10: avctx->time_base.den = 90000; yading@10: yading@10: if (buf && buf_size) { yading@10: switch(buf[0]) { yading@10: case 0x00: yading@10: if (buf_size == PCI_SIZE) { yading@10: /* PCI */ yading@10: uint32_t lba = AV_RB32(&buf[0x01]); yading@10: uint32_t startpts = AV_RB32(&buf[0x0D]); yading@10: uint32_t endpts = AV_RB32(&buf[0x11]); yading@10: yading@10: if (endpts > startpts) { yading@10: pc1->lba = lba; yading@10: s->pts = (int64_t)startpts; yading@10: s->duration = endpts - startpts; yading@10: yading@10: memcpy(pc1->buffer, buf, PCI_SIZE); yading@10: pc1->copied = PCI_SIZE; yading@10: valid = 1; yading@10: } yading@10: } yading@10: break; yading@10: yading@10: case 0x01: yading@10: if ((buf_size == DSI_SIZE) && (pc1->copied == PCI_SIZE)) { yading@10: /* DSI */ yading@10: uint32_t lba = AV_RB32(&buf[0x05]); yading@10: yading@10: if (lba == pc1->lba) { yading@10: memcpy(pc1->buffer + pc1->copied, buf, DSI_SIZE); yading@10: lastPacket = 1; yading@10: valid = 1; yading@10: } yading@10: } yading@10: break; yading@10: } yading@10: } yading@10: yading@10: if (!valid || lastPacket) { yading@10: pc1->copied = 0; yading@10: pc1->lba = 0xFFFFFFFF; yading@10: } yading@10: yading@10: if (lastPacket) { yading@10: *poutbuf = pc1->buffer; yading@10: *poutbuf_size = sizeof(pc1->buffer); yading@10: } else { yading@10: *poutbuf = NULL; yading@10: *poutbuf_size = 0; yading@10: } yading@10: yading@10: return buf_size; yading@10: } yading@10: yading@10: AVCodecParser ff_dvd_nav_parser = { yading@10: .codec_ids = { AV_CODEC_ID_DVD_NAV }, yading@10: .priv_data_size = sizeof(DVDNavParseContext), yading@10: .parser_init = dvd_nav_parse_init, yading@10: .parser_parse = dvd_nav_parse, yading@10: };