1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Metadata demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2010 Anton Khirnov 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/bprint.h" 23cabdff1aSopenharmony_ci#include "libavutil/mathematics.h" 24cabdff1aSopenharmony_ci#include "avformat.h" 25cabdff1aSopenharmony_ci#include "demux.h" 26cabdff1aSopenharmony_ci#include "ffmeta.h" 27cabdff1aSopenharmony_ci#include "libavutil/dict.h" 28cabdff1aSopenharmony_ci 29cabdff1aSopenharmony_cistatic int probe(const AVProbeData *p) 30cabdff1aSopenharmony_ci{ 31cabdff1aSopenharmony_ci if(!memcmp(p->buf, ID_STRING, strlen(ID_STRING))) 32cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 33cabdff1aSopenharmony_ci return 0; 34cabdff1aSopenharmony_ci} 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_cistatic int64_t read_line_to_bprint_escaped(AVIOContext *s, AVBPrint *bp) 37cabdff1aSopenharmony_ci{ 38cabdff1aSopenharmony_ci int len, end; 39cabdff1aSopenharmony_ci int64_t read = 0; 40cabdff1aSopenharmony_ci char tmp[1024]; 41cabdff1aSopenharmony_ci char c; 42cabdff1aSopenharmony_ci char prev = ' '; 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_ci do { 45cabdff1aSopenharmony_ci len = 0; 46cabdff1aSopenharmony_ci do { 47cabdff1aSopenharmony_ci c = avio_r8(s); 48cabdff1aSopenharmony_ci end = prev != '\\' && (c == '\r' || c == '\n' || c == '\0'); 49cabdff1aSopenharmony_ci if (!end) 50cabdff1aSopenharmony_ci tmp[len++] = c; 51cabdff1aSopenharmony_ci prev = c; 52cabdff1aSopenharmony_ci } while (!end && len < sizeof(tmp)); 53cabdff1aSopenharmony_ci av_bprint_append_data(bp, tmp, len); 54cabdff1aSopenharmony_ci read += len; 55cabdff1aSopenharmony_ci } while (!end); 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_ci if (c == '\r' && avio_r8(s) != '\n' && !avio_feof(s)) 58cabdff1aSopenharmony_ci avio_skip(s, -1); 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci if (!c && s->error) 61cabdff1aSopenharmony_ci return s->error; 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci if (!c && !read && avio_feof(s)) 64cabdff1aSopenharmony_ci return AVERROR_EOF; 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_ci return read; 67cabdff1aSopenharmony_ci} 68cabdff1aSopenharmony_ci 69cabdff1aSopenharmony_cistatic void get_bprint_line(AVIOContext *s, AVBPrint *bp) 70cabdff1aSopenharmony_ci{ 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_ci do { 73cabdff1aSopenharmony_ci av_bprint_clear(bp); 74cabdff1aSopenharmony_ci read_line_to_bprint_escaped(s, bp); 75cabdff1aSopenharmony_ci } while (!avio_feof(s) && (bp->str[0] == ';' || bp->str[0] == '#' || bp->str[0] == 0)); 76cabdff1aSopenharmony_ci} 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_cistatic void get_line(AVIOContext *s, uint8_t *buf, int size) 79cabdff1aSopenharmony_ci{ 80cabdff1aSopenharmony_ci do { 81cabdff1aSopenharmony_ci uint8_t c; 82cabdff1aSopenharmony_ci int i = 0; 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci while ((c = avio_r8(s))) { 85cabdff1aSopenharmony_ci if (c == '\\') { 86cabdff1aSopenharmony_ci if (i < size - 1) 87cabdff1aSopenharmony_ci buf[i++] = c; 88cabdff1aSopenharmony_ci c = avio_r8(s); 89cabdff1aSopenharmony_ci } else if (c == '\n') 90cabdff1aSopenharmony_ci break; 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_ci if (i < size - 1) 93cabdff1aSopenharmony_ci buf[i++] = c; 94cabdff1aSopenharmony_ci } 95cabdff1aSopenharmony_ci buf[i] = 0; 96cabdff1aSopenharmony_ci } while (!avio_feof(s) && (buf[0] == ';' || buf[0] == '#' || buf[0] == 0)); 97cabdff1aSopenharmony_ci} 98cabdff1aSopenharmony_ci 99cabdff1aSopenharmony_cistatic AVChapter *read_chapter(AVFormatContext *s) 100cabdff1aSopenharmony_ci{ 101cabdff1aSopenharmony_ci uint8_t line[256]; 102cabdff1aSopenharmony_ci int64_t start, end; 103cabdff1aSopenharmony_ci AVRational tb = {1, 1e9}; 104cabdff1aSopenharmony_ci int ret; 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci get_line(s->pb, line, sizeof(line)); 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci if (sscanf(line, "TIMEBASE=%d/%d", &tb.num, &tb.den)) 109cabdff1aSopenharmony_ci get_line(s->pb, line, sizeof(line)); 110cabdff1aSopenharmony_ci ret = sscanf(line, "START=%"SCNd64, &start); 111cabdff1aSopenharmony_ci if (ret <= 0) { 112cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Expected chapter start timestamp, found %s.\n", line); 113cabdff1aSopenharmony_ci start = (s->nb_chapters && s->chapters[s->nb_chapters - 1]->end != AV_NOPTS_VALUE) ? 114cabdff1aSopenharmony_ci s->chapters[s->nb_chapters - 1]->end : 0; 115cabdff1aSopenharmony_ci } else 116cabdff1aSopenharmony_ci get_line(s->pb, line, sizeof(line)); 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci ret = sscanf(line, "END=%"SCNd64, &end); 119cabdff1aSopenharmony_ci if (ret <= 0) { 120cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Expected chapter end timestamp, found %s.\n", line); 121cabdff1aSopenharmony_ci end = AV_NOPTS_VALUE; 122cabdff1aSopenharmony_ci } 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci return avpriv_new_chapter(s, s->nb_chapters, tb, start, end, NULL); 125cabdff1aSopenharmony_ci} 126cabdff1aSopenharmony_ci 127cabdff1aSopenharmony_cistatic uint8_t *unescape(const uint8_t *buf, int size) 128cabdff1aSopenharmony_ci{ 129cabdff1aSopenharmony_ci uint8_t *ret = av_malloc(size + 1); 130cabdff1aSopenharmony_ci uint8_t *p1 = ret; 131cabdff1aSopenharmony_ci const uint8_t *p2 = buf; 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci if (!ret) 134cabdff1aSopenharmony_ci return NULL; 135cabdff1aSopenharmony_ci 136cabdff1aSopenharmony_ci while (p2 < buf + size) { 137cabdff1aSopenharmony_ci if (*p2 == '\\') 138cabdff1aSopenharmony_ci p2++; 139cabdff1aSopenharmony_ci *p1++ = *p2++; 140cabdff1aSopenharmony_ci } 141cabdff1aSopenharmony_ci *p1 = 0; 142cabdff1aSopenharmony_ci return ret; 143cabdff1aSopenharmony_ci} 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_cistatic int read_tag(const uint8_t *line, AVDictionary **m) 146cabdff1aSopenharmony_ci{ 147cabdff1aSopenharmony_ci uint8_t *key, *value; 148cabdff1aSopenharmony_ci const uint8_t *p = line; 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci /* find first not escaped '=' */ 151cabdff1aSopenharmony_ci while (1) { 152cabdff1aSopenharmony_ci if (*p == '=') 153cabdff1aSopenharmony_ci break; 154cabdff1aSopenharmony_ci else if (*p == '\\') 155cabdff1aSopenharmony_ci p++; 156cabdff1aSopenharmony_ci 157cabdff1aSopenharmony_ci if (*p++) 158cabdff1aSopenharmony_ci continue; 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_ci return 0; 161cabdff1aSopenharmony_ci } 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci if (!(key = unescape(line, p - line))) 164cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 165cabdff1aSopenharmony_ci if (!(value = unescape(p + 1, strlen(p + 1)))) { 166cabdff1aSopenharmony_ci av_free(key); 167cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 168cabdff1aSopenharmony_ci } 169cabdff1aSopenharmony_ci 170cabdff1aSopenharmony_ci av_dict_set(m, key, value, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); 171cabdff1aSopenharmony_ci return 0; 172cabdff1aSopenharmony_ci} 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_cistatic int read_header(AVFormatContext *s) 175cabdff1aSopenharmony_ci{ 176cabdff1aSopenharmony_ci AVDictionary **m = &s->metadata; 177cabdff1aSopenharmony_ci AVBPrint bp; 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_ci av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_ci while(!avio_feof(s->pb)) { 182cabdff1aSopenharmony_ci get_bprint_line(s->pb, &bp); 183cabdff1aSopenharmony_ci 184cabdff1aSopenharmony_ci if (!memcmp(bp.str, ID_STREAM, strlen(ID_STREAM))) { 185cabdff1aSopenharmony_ci AVStream *st = avformat_new_stream(s, NULL); 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci if (!st) 188cabdff1aSopenharmony_ci goto nomem; 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_DATA; 191cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_FFMETADATA; 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_ci m = &st->metadata; 194cabdff1aSopenharmony_ci } else if (!memcmp(bp.str, ID_CHAPTER, strlen(ID_CHAPTER))) { 195cabdff1aSopenharmony_ci AVChapter *ch = read_chapter(s); 196cabdff1aSopenharmony_ci 197cabdff1aSopenharmony_ci if (!ch) 198cabdff1aSopenharmony_ci goto nomem; 199cabdff1aSopenharmony_ci 200cabdff1aSopenharmony_ci m = &ch->metadata; 201cabdff1aSopenharmony_ci } else 202cabdff1aSopenharmony_ci read_tag(bp.str, m); 203cabdff1aSopenharmony_ci } 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_ci av_bprint_finalize(&bp, NULL); 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci s->start_time = 0; 208cabdff1aSopenharmony_ci if (s->nb_chapters) 209cabdff1aSopenharmony_ci s->duration = av_rescale_q(s->chapters[s->nb_chapters - 1]->end, 210cabdff1aSopenharmony_ci s->chapters[s->nb_chapters - 1]->time_base, 211cabdff1aSopenharmony_ci AV_TIME_BASE_Q); 212cabdff1aSopenharmony_ci 213cabdff1aSopenharmony_ci return 0; 214cabdff1aSopenharmony_cinomem: 215cabdff1aSopenharmony_ci av_bprint_finalize(&bp, NULL); 216cabdff1aSopenharmony_ci 217cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 218cabdff1aSopenharmony_ci} 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_cistatic int read_packet(AVFormatContext *s, AVPacket *pkt) 221cabdff1aSopenharmony_ci{ 222cabdff1aSopenharmony_ci return AVERROR_EOF; 223cabdff1aSopenharmony_ci} 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ciconst AVInputFormat ff_ffmetadata_demuxer = { 226cabdff1aSopenharmony_ci .name = "ffmetadata", 227cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("FFmpeg metadata in text"), 228cabdff1aSopenharmony_ci .read_probe = probe, 229cabdff1aSopenharmony_ci .read_header = read_header, 230cabdff1aSopenharmony_ci .read_packet = read_packet, 231cabdff1aSopenharmony_ci}; 232