1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (C) 2005 Michael Ahlberg, Måns Rullgård 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * Permission is hereby granted, free of charge, to any person 5cabdff1aSopenharmony_ci * obtaining a copy of this software and associated documentation 6cabdff1aSopenharmony_ci * files (the "Software"), to deal in the Software without 7cabdff1aSopenharmony_ci * restriction, including without limitation the rights to use, copy, 8cabdff1aSopenharmony_ci * modify, merge, publish, distribute, sublicense, and/or sell copies 9cabdff1aSopenharmony_ci * of the Software, and to permit persons to whom the Software is 10cabdff1aSopenharmony_ci * furnished to do so, subject to the following conditions: 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * The above copyright notice and this permission notice shall be 13cabdff1aSopenharmony_ci * included in all copies or substantial portions of the Software. 14cabdff1aSopenharmony_ci * 15cabdff1aSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16cabdff1aSopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17cabdff1aSopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18cabdff1aSopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19cabdff1aSopenharmony_ci * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20cabdff1aSopenharmony_ci * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21cabdff1aSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22cabdff1aSopenharmony_ci * DEALINGS IN THE SOFTWARE. 23cabdff1aSopenharmony_ci */ 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include <stdlib.h> 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 28cabdff1aSopenharmony_ci#include "libavutil/base64.h" 29cabdff1aSopenharmony_ci#include "libavutil/dict.h" 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_ci#include "libavcodec/bytestream.h" 32cabdff1aSopenharmony_ci#include "libavcodec/vorbis_parser.h" 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_ci#include "avformat.h" 35cabdff1aSopenharmony_ci#include "demux.h" 36cabdff1aSopenharmony_ci#include "flac_picture.h" 37cabdff1aSopenharmony_ci#include "internal.h" 38cabdff1aSopenharmony_ci#include "oggdec.h" 39cabdff1aSopenharmony_ci#include "vorbiscomment.h" 40cabdff1aSopenharmony_ci#include "replaygain.h" 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_cistatic int ogm_chapter(AVFormatContext *as, const uint8_t *key, const uint8_t *val) 43cabdff1aSopenharmony_ci{ 44cabdff1aSopenharmony_ci int i, cnum, h, m, s, ms, keylen = strlen(key); 45cabdff1aSopenharmony_ci AVChapter *chapter = NULL; 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_ci if (keylen < 9 || av_strncasecmp(key, "CHAPTER", 7) || sscanf(key+7, "%03d", &cnum) != 1) 48cabdff1aSopenharmony_ci return 0; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci if (keylen <= 10) { 51cabdff1aSopenharmony_ci if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4) 52cabdff1aSopenharmony_ci return 0; 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_ci avpriv_new_chapter(as, cnum, (AVRational) { 1, 1000 }, 55cabdff1aSopenharmony_ci ms + 1000 * (s + 60 * (m + 60 * h)), 56cabdff1aSopenharmony_ci AV_NOPTS_VALUE, NULL); 57cabdff1aSopenharmony_ci } else if (!av_strcasecmp(key + keylen - 4, "NAME")) { 58cabdff1aSopenharmony_ci for (i = 0; i < as->nb_chapters; i++) 59cabdff1aSopenharmony_ci if (as->chapters[i]->id == cnum) { 60cabdff1aSopenharmony_ci chapter = as->chapters[i]; 61cabdff1aSopenharmony_ci break; 62cabdff1aSopenharmony_ci } 63cabdff1aSopenharmony_ci if (!chapter) 64cabdff1aSopenharmony_ci return 0; 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_ci av_dict_set(&chapter->metadata, "title", val, 0); 67cabdff1aSopenharmony_ci } else 68cabdff1aSopenharmony_ci return 0; 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci return 1; 71cabdff1aSopenharmony_ci} 72cabdff1aSopenharmony_ci 73cabdff1aSopenharmony_ciint ff_vorbis_stream_comment(AVFormatContext *as, AVStream *st, 74cabdff1aSopenharmony_ci const uint8_t *buf, int size) 75cabdff1aSopenharmony_ci{ 76cabdff1aSopenharmony_ci int updates = ff_vorbis_comment(as, &st->metadata, buf, size, 1); 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci if (updates > 0) { 79cabdff1aSopenharmony_ci st->event_flags |= AVSTREAM_EVENT_FLAG_METADATA_UPDATED; 80cabdff1aSopenharmony_ci } 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_ci return updates; 83cabdff1aSopenharmony_ci} 84cabdff1aSopenharmony_ci 85cabdff1aSopenharmony_ci/** 86cabdff1aSopenharmony_ci * This function temporarily modifies the (const qualified) input buffer 87cabdff1aSopenharmony_ci * and reverts its changes before return. The input buffer needs to have 88cabdff1aSopenharmony_ci * at least one byte of padding. 89cabdff1aSopenharmony_ci */ 90cabdff1aSopenharmony_cistatic int vorbis_parse_single_comment(AVFormatContext *as, AVDictionary **m, 91cabdff1aSopenharmony_ci const uint8_t *buf, uint32_t size, 92cabdff1aSopenharmony_ci int *updates, int parse_picture) 93cabdff1aSopenharmony_ci{ 94cabdff1aSopenharmony_ci char *t = (char*)buf, *v = memchr(t, '=', size); 95cabdff1aSopenharmony_ci int tl, vl; 96cabdff1aSopenharmony_ci char backup; 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_ci if (!v) 99cabdff1aSopenharmony_ci return 0; 100cabdff1aSopenharmony_ci 101cabdff1aSopenharmony_ci tl = v - t; 102cabdff1aSopenharmony_ci vl = size - tl - 1; 103cabdff1aSopenharmony_ci v++; 104cabdff1aSopenharmony_ci 105cabdff1aSopenharmony_ci if (!tl || !vl) 106cabdff1aSopenharmony_ci return 0; 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci t[tl] = 0; 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_ci backup = v[vl]; 111cabdff1aSopenharmony_ci v[vl] = 0; 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_ci /* The format in which the pictures are stored is the FLAC format. 114cabdff1aSopenharmony_ci * Xiph says: "The binary FLAC picture structure is base64 encoded 115cabdff1aSopenharmony_ci * and placed within a VorbisComment with the tag name 116cabdff1aSopenharmony_ci * 'METADATA_BLOCK_PICTURE'. This is the preferred and 117cabdff1aSopenharmony_ci * recommended way of embedding cover art within VorbisComments." 118cabdff1aSopenharmony_ci */ 119cabdff1aSopenharmony_ci if (!av_strcasecmp(t, "METADATA_BLOCK_PICTURE") && parse_picture) { 120cabdff1aSopenharmony_ci int ret, len = AV_BASE64_DECODE_SIZE(vl); 121cabdff1aSopenharmony_ci uint8_t *pict = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE); 122cabdff1aSopenharmony_ci 123cabdff1aSopenharmony_ci if (!pict) { 124cabdff1aSopenharmony_ci av_log(as, AV_LOG_WARNING, "out-of-memory error. Skipping cover art block.\n"); 125cabdff1aSopenharmony_ci goto end; 126cabdff1aSopenharmony_ci } 127cabdff1aSopenharmony_ci ret = av_base64_decode(pict, v, len); 128cabdff1aSopenharmony_ci if (ret > 0) 129cabdff1aSopenharmony_ci ret = ff_flac_parse_picture(as, &pict, ret, 0); 130cabdff1aSopenharmony_ci av_freep(&pict); 131cabdff1aSopenharmony_ci if (ret < 0) { 132cabdff1aSopenharmony_ci av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n"); 133cabdff1aSopenharmony_ci goto end; 134cabdff1aSopenharmony_ci } 135cabdff1aSopenharmony_ci } else if (!ogm_chapter(as, t, v)) { 136cabdff1aSopenharmony_ci (*updates)++; 137cabdff1aSopenharmony_ci if (av_dict_get(*m, t, NULL, 0)) 138cabdff1aSopenharmony_ci av_dict_set(m, t, ";", AV_DICT_APPEND); 139cabdff1aSopenharmony_ci av_dict_set(m, t, v, AV_DICT_APPEND); 140cabdff1aSopenharmony_ci } 141cabdff1aSopenharmony_ciend: 142cabdff1aSopenharmony_ci t[tl] = '='; 143cabdff1aSopenharmony_ci v[vl] = backup; 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_ci return 0; 146cabdff1aSopenharmony_ci} 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ciint ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, 149cabdff1aSopenharmony_ci const uint8_t *buf, int size, 150cabdff1aSopenharmony_ci int parse_picture) 151cabdff1aSopenharmony_ci{ 152cabdff1aSopenharmony_ci const uint8_t *p = buf; 153cabdff1aSopenharmony_ci const uint8_t *end = buf + size; 154cabdff1aSopenharmony_ci int updates = 0; 155cabdff1aSopenharmony_ci unsigned n; 156cabdff1aSopenharmony_ci int s, ret; 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci /* must have vendor_length and user_comment_list_length */ 159cabdff1aSopenharmony_ci if (size < 8) 160cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_ci s = bytestream_get_le32(&p); 163cabdff1aSopenharmony_ci 164cabdff1aSopenharmony_ci if (end - p - 4 < s || s < 0) 165cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 166cabdff1aSopenharmony_ci 167cabdff1aSopenharmony_ci p += s; 168cabdff1aSopenharmony_ci 169cabdff1aSopenharmony_ci n = bytestream_get_le32(&p); 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_ci while (end - p >= 4 && n > 0) { 172cabdff1aSopenharmony_ci s = bytestream_get_le32(&p); 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_ci if (end - p < s || s < 0) 175cabdff1aSopenharmony_ci break; 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci ret = vorbis_parse_single_comment(as, m, p, s, &updates, parse_picture); 178cabdff1aSopenharmony_ci if (ret < 0) 179cabdff1aSopenharmony_ci return ret; 180cabdff1aSopenharmony_ci p += s; 181cabdff1aSopenharmony_ci n--; 182cabdff1aSopenharmony_ci } 183cabdff1aSopenharmony_ci 184cabdff1aSopenharmony_ci if (p != end) 185cabdff1aSopenharmony_ci av_log(as, AV_LOG_INFO, 186cabdff1aSopenharmony_ci "%"PTRDIFF_SPECIFIER" bytes of comment header remain\n", end - p); 187cabdff1aSopenharmony_ci if (n > 0) 188cabdff1aSopenharmony_ci av_log(as, AV_LOG_INFO, 189cabdff1aSopenharmony_ci "truncated comment header, %i comments not found\n", n); 190cabdff1aSopenharmony_ci 191cabdff1aSopenharmony_ci ff_metadata_conv(m, NULL, ff_vorbiscomment_metadata_conv); 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_ci return updates; 194cabdff1aSopenharmony_ci} 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_ci/* 197cabdff1aSopenharmony_ci * Parse the vorbis header 198cabdff1aSopenharmony_ci * 199cabdff1aSopenharmony_ci * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec 200cabdff1aSopenharmony_ci * [vorbis_version] = read 32 bits as unsigned integer | Not used 201cabdff1aSopenharmony_ci * [audio_channels] = read 8 bit integer as unsigned | Used 202cabdff1aSopenharmony_ci * [audio_sample_rate] = read 32 bits as unsigned integer | Used 203cabdff1aSopenharmony_ci * [bitrate_maximum] = read 32 bits as signed integer | Not used yet 204cabdff1aSopenharmony_ci * [bitrate_nominal] = read 32 bits as signed integer | Not used yet 205cabdff1aSopenharmony_ci * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate 206cabdff1aSopenharmony_ci * [blocksize_0] = read 4 bits as unsigned integer | Not Used 207cabdff1aSopenharmony_ci * [blocksize_1] = read 4 bits as unsigned integer | Not Used 208cabdff1aSopenharmony_ci * [framing_flag] = read one bit | Not Used 209cabdff1aSopenharmony_ci */ 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_cistruct oggvorbis_private { 212cabdff1aSopenharmony_ci unsigned int len[3]; 213cabdff1aSopenharmony_ci unsigned char *packet[3]; 214cabdff1aSopenharmony_ci AVVorbisParseContext *vp; 215cabdff1aSopenharmony_ci int64_t final_pts; 216cabdff1aSopenharmony_ci int final_duration; 217cabdff1aSopenharmony_ci}; 218cabdff1aSopenharmony_ci 219cabdff1aSopenharmony_cistatic int fixup_vorbis_headers(AVFormatContext *as, 220cabdff1aSopenharmony_ci struct oggvorbis_private *priv, 221cabdff1aSopenharmony_ci uint8_t **buf) 222cabdff1aSopenharmony_ci{ 223cabdff1aSopenharmony_ci int i, offset, len, err; 224cabdff1aSopenharmony_ci int buf_len; 225cabdff1aSopenharmony_ci unsigned char *ptr; 226cabdff1aSopenharmony_ci 227cabdff1aSopenharmony_ci len = priv->len[0] + priv->len[1] + priv->len[2]; 228cabdff1aSopenharmony_ci buf_len = len + len / 255 + 64; 229cabdff1aSopenharmony_ci 230cabdff1aSopenharmony_ci if (*buf) 231cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci ptr = *buf = av_realloc(NULL, buf_len); 234cabdff1aSopenharmony_ci if (!ptr) 235cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 236cabdff1aSopenharmony_ci memset(*buf, '\0', buf_len); 237cabdff1aSopenharmony_ci 238cabdff1aSopenharmony_ci ptr[0] = 2; 239cabdff1aSopenharmony_ci offset = 1; 240cabdff1aSopenharmony_ci offset += av_xiphlacing(&ptr[offset], priv->len[0]); 241cabdff1aSopenharmony_ci offset += av_xiphlacing(&ptr[offset], priv->len[1]); 242cabdff1aSopenharmony_ci for (i = 0; i < 3; i++) { 243cabdff1aSopenharmony_ci memcpy(&ptr[offset], priv->packet[i], priv->len[i]); 244cabdff1aSopenharmony_ci offset += priv->len[i]; 245cabdff1aSopenharmony_ci av_freep(&priv->packet[i]); 246cabdff1aSopenharmony_ci } 247cabdff1aSopenharmony_ci if ((err = av_reallocp(buf, offset + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) 248cabdff1aSopenharmony_ci return err; 249cabdff1aSopenharmony_ci return offset; 250cabdff1aSopenharmony_ci} 251cabdff1aSopenharmony_ci 252cabdff1aSopenharmony_cistatic void vorbis_cleanup(AVFormatContext *s, int idx) 253cabdff1aSopenharmony_ci{ 254cabdff1aSopenharmony_ci struct ogg *ogg = s->priv_data; 255cabdff1aSopenharmony_ci struct ogg_stream *os = ogg->streams + idx; 256cabdff1aSopenharmony_ci struct oggvorbis_private *priv = os->private; 257cabdff1aSopenharmony_ci int i; 258cabdff1aSopenharmony_ci if (os->private) { 259cabdff1aSopenharmony_ci av_vorbis_parse_free(&priv->vp); 260cabdff1aSopenharmony_ci for (i = 0; i < 3; i++) 261cabdff1aSopenharmony_ci av_freep(&priv->packet[i]); 262cabdff1aSopenharmony_ci } 263cabdff1aSopenharmony_ci} 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_cistatic int vorbis_update_metadata(AVFormatContext *s, int idx) 266cabdff1aSopenharmony_ci{ 267cabdff1aSopenharmony_ci struct ogg *ogg = s->priv_data; 268cabdff1aSopenharmony_ci struct ogg_stream *os = ogg->streams + idx; 269cabdff1aSopenharmony_ci AVStream *st = s->streams[idx]; 270cabdff1aSopenharmony_ci int ret; 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci if (os->psize <= 8) 273cabdff1aSopenharmony_ci return 0; 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_ci /* New metadata packet; release old data. */ 276cabdff1aSopenharmony_ci av_dict_free(&st->metadata); 277cabdff1aSopenharmony_ci ret = ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7, 278cabdff1aSopenharmony_ci os->psize - 8); 279cabdff1aSopenharmony_ci if (ret < 0) 280cabdff1aSopenharmony_ci return ret; 281cabdff1aSopenharmony_ci 282cabdff1aSopenharmony_ci /* Update the metadata if possible. */ 283cabdff1aSopenharmony_ci av_freep(&os->new_metadata); 284cabdff1aSopenharmony_ci if (st->metadata) { 285cabdff1aSopenharmony_ci os->new_metadata = av_packet_pack_dictionary(st->metadata, &os->new_metadata_size); 286cabdff1aSopenharmony_ci /* Send an empty dictionary to indicate that metadata has been cleared. */ 287cabdff1aSopenharmony_ci } else { 288cabdff1aSopenharmony_ci os->new_metadata = av_mallocz(1); 289cabdff1aSopenharmony_ci os->new_metadata_size = 0; 290cabdff1aSopenharmony_ci } 291cabdff1aSopenharmony_ci 292cabdff1aSopenharmony_ci return ret; 293cabdff1aSopenharmony_ci} 294cabdff1aSopenharmony_ci 295cabdff1aSopenharmony_cistatic int vorbis_header(AVFormatContext *s, int idx) 296cabdff1aSopenharmony_ci{ 297cabdff1aSopenharmony_ci struct ogg *ogg = s->priv_data; 298cabdff1aSopenharmony_ci AVStream *st = s->streams[idx]; 299cabdff1aSopenharmony_ci struct ogg_stream *os = ogg->streams + idx; 300cabdff1aSopenharmony_ci struct oggvorbis_private *priv; 301cabdff1aSopenharmony_ci int pkt_type = os->buf[os->pstart]; 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci if (!os->private) { 304cabdff1aSopenharmony_ci os->private = av_mallocz(sizeof(struct oggvorbis_private)); 305cabdff1aSopenharmony_ci if (!os->private) 306cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 307cabdff1aSopenharmony_ci } 308cabdff1aSopenharmony_ci 309cabdff1aSopenharmony_ci priv = os->private; 310cabdff1aSopenharmony_ci 311cabdff1aSopenharmony_ci if (!(pkt_type & 1)) 312cabdff1aSopenharmony_ci return priv->vp ? 0 : AVERROR_INVALIDDATA; 313cabdff1aSopenharmony_ci 314cabdff1aSopenharmony_ci if (os->psize < 1 || pkt_type > 5) 315cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci if (priv->packet[pkt_type >> 1]) 318cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 319cabdff1aSopenharmony_ci if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1]) 320cabdff1aSopenharmony_ci return priv->vp ? 0 : AVERROR_INVALIDDATA; 321cabdff1aSopenharmony_ci 322cabdff1aSopenharmony_ci priv->len[pkt_type >> 1] = os->psize; 323cabdff1aSopenharmony_ci priv->packet[pkt_type >> 1] = av_memdup(os->buf + os->pstart, os->psize); 324cabdff1aSopenharmony_ci if (!priv->packet[pkt_type >> 1]) 325cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 326cabdff1aSopenharmony_ci if (os->buf[os->pstart] == 1) { 327cabdff1aSopenharmony_ci const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */ 328cabdff1aSopenharmony_ci unsigned blocksize, bs0, bs1; 329cabdff1aSopenharmony_ci int srate; 330cabdff1aSopenharmony_ci int channels; 331cabdff1aSopenharmony_ci 332cabdff1aSopenharmony_ci if (os->psize != 30) 333cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 334cabdff1aSopenharmony_ci 335cabdff1aSopenharmony_ci if (bytestream_get_le32(&p) != 0) /* vorbis_version */ 336cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 337cabdff1aSopenharmony_ci 338cabdff1aSopenharmony_ci channels = bytestream_get_byte(&p); 339cabdff1aSopenharmony_ci if (st->codecpar->ch_layout.nb_channels && 340cabdff1aSopenharmony_ci channels != st->codecpar->ch_layout.nb_channels) { 341cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Channel change is not supported\n"); 342cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 343cabdff1aSopenharmony_ci } 344cabdff1aSopenharmony_ci st->codecpar->ch_layout.nb_channels = channels; 345cabdff1aSopenharmony_ci srate = bytestream_get_le32(&p); 346cabdff1aSopenharmony_ci p += 4; // skip maximum bitrate 347cabdff1aSopenharmony_ci st->codecpar->bit_rate = bytestream_get_le32(&p); // nominal bitrate 348cabdff1aSopenharmony_ci p += 4; // skip minimum bitrate 349cabdff1aSopenharmony_ci 350cabdff1aSopenharmony_ci blocksize = bytestream_get_byte(&p); 351cabdff1aSopenharmony_ci bs0 = blocksize & 15; 352cabdff1aSopenharmony_ci bs1 = blocksize >> 4; 353cabdff1aSopenharmony_ci 354cabdff1aSopenharmony_ci if (bs0 > bs1) 355cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 356cabdff1aSopenharmony_ci if (bs0 < 6 || bs1 > 13) 357cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 358cabdff1aSopenharmony_ci 359cabdff1aSopenharmony_ci if (bytestream_get_byte(&p) != 1) /* framing_flag */ 360cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 361cabdff1aSopenharmony_ci 362cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 363cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_VORBIS; 364cabdff1aSopenharmony_ci 365cabdff1aSopenharmony_ci if (srate > 0) { 366cabdff1aSopenharmony_ci st->codecpar->sample_rate = srate; 367cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, 1, srate); 368cabdff1aSopenharmony_ci } 369cabdff1aSopenharmony_ci } else if (os->buf[os->pstart] == 3) { 370cabdff1aSopenharmony_ci if (vorbis_update_metadata(s, idx) >= 0 && priv->len[1] > 10) { 371cabdff1aSopenharmony_ci unsigned new_len; 372cabdff1aSopenharmony_ci 373cabdff1aSopenharmony_ci int ret = ff_replaygain_export(st, st->metadata); 374cabdff1aSopenharmony_ci if (ret < 0) 375cabdff1aSopenharmony_ci return ret; 376cabdff1aSopenharmony_ci 377cabdff1aSopenharmony_ci // drop all metadata we parsed and which is not required by libvorbis 378cabdff1aSopenharmony_ci new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1; 379cabdff1aSopenharmony_ci if (new_len >= 16 && new_len < os->psize) { 380cabdff1aSopenharmony_ci AV_WL32(priv->packet[1] + new_len - 5, 0); 381cabdff1aSopenharmony_ci priv->packet[1][new_len - 1] = 1; 382cabdff1aSopenharmony_ci priv->len[1] = new_len; 383cabdff1aSopenharmony_ci } 384cabdff1aSopenharmony_ci } 385cabdff1aSopenharmony_ci } else { 386cabdff1aSopenharmony_ci int ret; 387cabdff1aSopenharmony_ci 388cabdff1aSopenharmony_ci if (priv->vp) 389cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 390cabdff1aSopenharmony_ci 391cabdff1aSopenharmony_ci ret = fixup_vorbis_headers(s, priv, &st->codecpar->extradata); 392cabdff1aSopenharmony_ci if (ret < 0) { 393cabdff1aSopenharmony_ci st->codecpar->extradata_size = 0; 394cabdff1aSopenharmony_ci return ret; 395cabdff1aSopenharmony_ci } 396cabdff1aSopenharmony_ci st->codecpar->extradata_size = ret; 397cabdff1aSopenharmony_ci 398cabdff1aSopenharmony_ci priv->vp = av_vorbis_parse_init(st->codecpar->extradata, st->codecpar->extradata_size); 399cabdff1aSopenharmony_ci if (!priv->vp) { 400cabdff1aSopenharmony_ci av_freep(&st->codecpar->extradata); 401cabdff1aSopenharmony_ci st->codecpar->extradata_size = 0; 402cabdff1aSopenharmony_ci return AVERROR_UNKNOWN; 403cabdff1aSopenharmony_ci } 404cabdff1aSopenharmony_ci } 405cabdff1aSopenharmony_ci 406cabdff1aSopenharmony_ci return 1; 407cabdff1aSopenharmony_ci} 408cabdff1aSopenharmony_ci 409cabdff1aSopenharmony_cistatic int vorbis_packet(AVFormatContext *s, int idx) 410cabdff1aSopenharmony_ci{ 411cabdff1aSopenharmony_ci struct ogg *ogg = s->priv_data; 412cabdff1aSopenharmony_ci struct ogg_stream *os = ogg->streams + idx; 413cabdff1aSopenharmony_ci struct oggvorbis_private *priv = os->private; 414cabdff1aSopenharmony_ci int duration, flags = 0; 415cabdff1aSopenharmony_ci 416cabdff1aSopenharmony_ci if (!priv->vp) 417cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 418cabdff1aSopenharmony_ci 419cabdff1aSopenharmony_ci /* first packet handling 420cabdff1aSopenharmony_ci * here we parse the duration of each packet in the first page and compare 421cabdff1aSopenharmony_ci * the total duration to the page granule to find the encoder delay and 422cabdff1aSopenharmony_ci * set the first timestamp */ 423cabdff1aSopenharmony_ci if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS) && (int64_t)os->granule>=0) { 424cabdff1aSopenharmony_ci int seg, d; 425cabdff1aSopenharmony_ci uint8_t *last_pkt = os->buf + os->pstart; 426cabdff1aSopenharmony_ci uint8_t *next_pkt = last_pkt; 427cabdff1aSopenharmony_ci 428cabdff1aSopenharmony_ci av_vorbis_parse_reset(priv->vp); 429cabdff1aSopenharmony_ci duration = 0; 430cabdff1aSopenharmony_ci seg = os->segp; 431cabdff1aSopenharmony_ci d = av_vorbis_parse_frame_flags(priv->vp, last_pkt, 1, &flags); 432cabdff1aSopenharmony_ci if (d < 0) { 433cabdff1aSopenharmony_ci os->pflags |= AV_PKT_FLAG_CORRUPT; 434cabdff1aSopenharmony_ci return 0; 435cabdff1aSopenharmony_ci } else if (flags & VORBIS_FLAG_COMMENT) { 436cabdff1aSopenharmony_ci vorbis_update_metadata(s, idx); 437cabdff1aSopenharmony_ci flags = 0; 438cabdff1aSopenharmony_ci } 439cabdff1aSopenharmony_ci duration += d; 440cabdff1aSopenharmony_ci last_pkt = next_pkt = next_pkt + os->psize; 441cabdff1aSopenharmony_ci for (; seg < os->nsegs; seg++) { 442cabdff1aSopenharmony_ci if (os->segments[seg] < 255) { 443cabdff1aSopenharmony_ci int d = av_vorbis_parse_frame_flags(priv->vp, last_pkt, 1, &flags); 444cabdff1aSopenharmony_ci if (d < 0) { 445cabdff1aSopenharmony_ci duration = os->granule; 446cabdff1aSopenharmony_ci break; 447cabdff1aSopenharmony_ci } else if (flags & VORBIS_FLAG_COMMENT) { 448cabdff1aSopenharmony_ci vorbis_update_metadata(s, idx); 449cabdff1aSopenharmony_ci flags = 0; 450cabdff1aSopenharmony_ci } 451cabdff1aSopenharmony_ci duration += d; 452cabdff1aSopenharmony_ci last_pkt = next_pkt + os->segments[seg]; 453cabdff1aSopenharmony_ci } 454cabdff1aSopenharmony_ci next_pkt += os->segments[seg]; 455cabdff1aSopenharmony_ci } 456cabdff1aSopenharmony_ci os->lastpts = 457cabdff1aSopenharmony_ci os->lastdts = os->granule - duration; 458cabdff1aSopenharmony_ci 459cabdff1aSopenharmony_ci if (!os->granule && duration) //hack to deal with broken files (Ticket3710) 460cabdff1aSopenharmony_ci os->lastpts = os->lastdts = AV_NOPTS_VALUE; 461cabdff1aSopenharmony_ci 462cabdff1aSopenharmony_ci if (s->streams[idx]->start_time == AV_NOPTS_VALUE) { 463cabdff1aSopenharmony_ci s->streams[idx]->start_time = FFMAX(os->lastpts, 0); 464cabdff1aSopenharmony_ci if (s->streams[idx]->duration != AV_NOPTS_VALUE) 465cabdff1aSopenharmony_ci s->streams[idx]->duration -= s->streams[idx]->start_time; 466cabdff1aSopenharmony_ci } 467cabdff1aSopenharmony_ci priv->final_pts = AV_NOPTS_VALUE; 468cabdff1aSopenharmony_ci av_vorbis_parse_reset(priv->vp); 469cabdff1aSopenharmony_ci } 470cabdff1aSopenharmony_ci 471cabdff1aSopenharmony_ci /* parse packet duration */ 472cabdff1aSopenharmony_ci if (os->psize > 0) { 473cabdff1aSopenharmony_ci duration = av_vorbis_parse_frame_flags(priv->vp, os->buf + os->pstart, 1, &flags); 474cabdff1aSopenharmony_ci if (duration < 0) { 475cabdff1aSopenharmony_ci os->pflags |= AV_PKT_FLAG_CORRUPT; 476cabdff1aSopenharmony_ci return 0; 477cabdff1aSopenharmony_ci } else if (flags & VORBIS_FLAG_COMMENT) { 478cabdff1aSopenharmony_ci vorbis_update_metadata(s, idx); 479cabdff1aSopenharmony_ci flags = 0; 480cabdff1aSopenharmony_ci } 481cabdff1aSopenharmony_ci os->pduration = duration; 482cabdff1aSopenharmony_ci } 483cabdff1aSopenharmony_ci 484cabdff1aSopenharmony_ci /* final packet handling 485cabdff1aSopenharmony_ci * here we save the pts of the first packet in the final page, sum up all 486cabdff1aSopenharmony_ci * packet durations in the final page except for the last one, and compare 487cabdff1aSopenharmony_ci * to the page granule to find the duration of the final packet */ 488cabdff1aSopenharmony_ci if (os->flags & OGG_FLAG_EOS) { 489cabdff1aSopenharmony_ci if (os->lastpts != AV_NOPTS_VALUE) { 490cabdff1aSopenharmony_ci priv->final_pts = os->lastpts; 491cabdff1aSopenharmony_ci priv->final_duration = 0; 492cabdff1aSopenharmony_ci } 493cabdff1aSopenharmony_ci if (os->segp == os->nsegs) { 494cabdff1aSopenharmony_ci int64_t skip = priv->final_pts + priv->final_duration + os->pduration - os->granule; 495cabdff1aSopenharmony_ci if (skip > 0) 496cabdff1aSopenharmony_ci os->end_trimming = skip; 497cabdff1aSopenharmony_ci os->pduration = os->granule - priv->final_pts - priv->final_duration; 498cabdff1aSopenharmony_ci } 499cabdff1aSopenharmony_ci priv->final_duration += os->pduration; 500cabdff1aSopenharmony_ci } 501cabdff1aSopenharmony_ci 502cabdff1aSopenharmony_ci return 0; 503cabdff1aSopenharmony_ci} 504cabdff1aSopenharmony_ci 505cabdff1aSopenharmony_ciconst struct ogg_codec ff_vorbis_codec = { 506cabdff1aSopenharmony_ci .magic = "\001vorbis", 507cabdff1aSopenharmony_ci .magicsize = 7, 508cabdff1aSopenharmony_ci .header = vorbis_header, 509cabdff1aSopenharmony_ci .packet = vorbis_packet, 510cabdff1aSopenharmony_ci .cleanup = vorbis_cleanup, 511cabdff1aSopenharmony_ci .nb_header = 3, 512cabdff1aSopenharmony_ci}; 513