1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * GXF demuxer. 3cabdff1aSopenharmony_ci * Copyright (c) 2006 Reimar Doeffinger 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 <inttypes.h> 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h" 25cabdff1aSopenharmony_ci#include "libavutil/common.h" 26cabdff1aSopenharmony_ci#include "avformat.h" 27cabdff1aSopenharmony_ci#include "demux.h" 28cabdff1aSopenharmony_ci#include "internal.h" 29cabdff1aSopenharmony_ci#include "gxf.h" 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_cistruct gxf_stream_info { 32cabdff1aSopenharmony_ci int64_t first_field; 33cabdff1aSopenharmony_ci int64_t last_field; 34cabdff1aSopenharmony_ci AVRational frames_per_second; 35cabdff1aSopenharmony_ci int32_t fields_per_frame; 36cabdff1aSopenharmony_ci int64_t track_aux_data; 37cabdff1aSopenharmony_ci}; 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci/** 40cabdff1aSopenharmony_ci * @brief parse gxf timecode and add it to metadata 41cabdff1aSopenharmony_ci */ 42cabdff1aSopenharmony_cistatic int add_timecode_metadata(AVDictionary **pm, const char *key, uint32_t timecode, int fields_per_frame) 43cabdff1aSopenharmony_ci{ 44cabdff1aSopenharmony_ci char tmp[128]; 45cabdff1aSopenharmony_ci int field = timecode & 0xff; 46cabdff1aSopenharmony_ci int frame = fields_per_frame ? field / fields_per_frame : field; 47cabdff1aSopenharmony_ci int second = (timecode >> 8) & 0xff; 48cabdff1aSopenharmony_ci int minute = (timecode >> 16) & 0xff; 49cabdff1aSopenharmony_ci int hour = (timecode >> 24) & 0x1f; 50cabdff1aSopenharmony_ci int drop = (timecode >> 29) & 1; 51cabdff1aSopenharmony_ci // bit 30: color_frame, unused 52cabdff1aSopenharmony_ci // ignore invalid time code 53cabdff1aSopenharmony_ci if (timecode >> 31) 54cabdff1aSopenharmony_ci return 0; 55cabdff1aSopenharmony_ci snprintf(tmp, sizeof(tmp), "%02d:%02d:%02d%c%02d", 56cabdff1aSopenharmony_ci hour, minute, second, drop ? ';' : ':', frame); 57cabdff1aSopenharmony_ci return av_dict_set(pm, key, tmp, 0); 58cabdff1aSopenharmony_ci} 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci/** 61cabdff1aSopenharmony_ci * @brief parses a packet header, extracting type and length 62cabdff1aSopenharmony_ci * @param pb AVIOContext to read header from 63cabdff1aSopenharmony_ci * @param type detected packet type is stored here 64cabdff1aSopenharmony_ci * @param length detected packet length, excluding header is stored here 65cabdff1aSopenharmony_ci * @return 0 if header not found or contains invalid data, 1 otherwise 66cabdff1aSopenharmony_ci */ 67cabdff1aSopenharmony_cistatic int parse_packet_header(AVIOContext *pb, GXFPktType *type, int *length) { 68cabdff1aSopenharmony_ci if (avio_rb32(pb)) 69cabdff1aSopenharmony_ci return 0; 70cabdff1aSopenharmony_ci if (avio_r8(pb) != 1) 71cabdff1aSopenharmony_ci return 0; 72cabdff1aSopenharmony_ci *type = avio_r8(pb); 73cabdff1aSopenharmony_ci *length = avio_rb32(pb); 74cabdff1aSopenharmony_ci if ((*length >> 24) || *length < 16) 75cabdff1aSopenharmony_ci return 0; 76cabdff1aSopenharmony_ci *length -= 16; 77cabdff1aSopenharmony_ci if (avio_rb32(pb)) 78cabdff1aSopenharmony_ci return 0; 79cabdff1aSopenharmony_ci if (avio_r8(pb) != 0xe1) 80cabdff1aSopenharmony_ci return 0; 81cabdff1aSopenharmony_ci if (avio_r8(pb) != 0xe2) 82cabdff1aSopenharmony_ci return 0; 83cabdff1aSopenharmony_ci return 1; 84cabdff1aSopenharmony_ci} 85cabdff1aSopenharmony_ci 86cabdff1aSopenharmony_ci/** 87cabdff1aSopenharmony_ci * @brief check if file starts with a PKT_MAP header 88cabdff1aSopenharmony_ci */ 89cabdff1aSopenharmony_cistatic int gxf_probe(const AVProbeData *p) { 90cabdff1aSopenharmony_ci static const uint8_t startcode[] = {0, 0, 0, 0, 1, 0xbc}; // start with map packet 91cabdff1aSopenharmony_ci static const uint8_t endcode[] = {0, 0, 0, 0, 0xe1, 0xe2}; 92cabdff1aSopenharmony_ci if (!memcmp(p->buf, startcode, sizeof(startcode)) && 93cabdff1aSopenharmony_ci !memcmp(&p->buf[16 - sizeof(endcode)], endcode, sizeof(endcode))) 94cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 95cabdff1aSopenharmony_ci return 0; 96cabdff1aSopenharmony_ci} 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_ci/** 99cabdff1aSopenharmony_ci * @brief gets the stream index for the track with the specified id, creates new 100cabdff1aSopenharmony_ci * stream if not found 101cabdff1aSopenharmony_ci * @param id id of stream to find / add 102cabdff1aSopenharmony_ci * @param format stream format identifier 103cabdff1aSopenharmony_ci */ 104cabdff1aSopenharmony_cistatic int get_sindex(AVFormatContext *s, int id, int format) { 105cabdff1aSopenharmony_ci int i; 106cabdff1aSopenharmony_ci AVStream *st = NULL; 107cabdff1aSopenharmony_ci FFStream *sti; 108cabdff1aSopenharmony_ci i = ff_find_stream_index(s, id); 109cabdff1aSopenharmony_ci if (i >= 0) 110cabdff1aSopenharmony_ci return i; 111cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 112cabdff1aSopenharmony_ci if (!st) 113cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 114cabdff1aSopenharmony_ci sti = ffstream(st); 115cabdff1aSopenharmony_ci st->id = id; 116cabdff1aSopenharmony_ci switch (format) { 117cabdff1aSopenharmony_ci case 3: 118cabdff1aSopenharmony_ci case 4: 119cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 120cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_MJPEG; 121cabdff1aSopenharmony_ci break; 122cabdff1aSopenharmony_ci case 13: 123cabdff1aSopenharmony_ci case 14: 124cabdff1aSopenharmony_ci case 15: 125cabdff1aSopenharmony_ci case 16: 126cabdff1aSopenharmony_ci case 25: 127cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 128cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_DVVIDEO; 129cabdff1aSopenharmony_ci break; 130cabdff1aSopenharmony_ci case 11: 131cabdff1aSopenharmony_ci case 12: 132cabdff1aSopenharmony_ci case 20: 133cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 134cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_MPEG2VIDEO; 135cabdff1aSopenharmony_ci sti->need_parsing = AVSTREAM_PARSE_HEADERS; //get keyframe flag etc. 136cabdff1aSopenharmony_ci break; 137cabdff1aSopenharmony_ci case 22: 138cabdff1aSopenharmony_ci case 23: 139cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 140cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_MPEG1VIDEO; 141cabdff1aSopenharmony_ci sti->need_parsing = AVSTREAM_PARSE_HEADERS; //get keyframe flag etc. 142cabdff1aSopenharmony_ci break; 143cabdff1aSopenharmony_ci case 9: 144cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 145cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_PCM_S24LE; 146cabdff1aSopenharmony_ci st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; 147cabdff1aSopenharmony_ci st->codecpar->sample_rate = 48000; 148cabdff1aSopenharmony_ci st->codecpar->bit_rate = 3 * 1 * 48000 * 8; 149cabdff1aSopenharmony_ci st->codecpar->block_align = 3 * 1; 150cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample = 24; 151cabdff1aSopenharmony_ci break; 152cabdff1aSopenharmony_ci case 10: 153cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 154cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; 155cabdff1aSopenharmony_ci st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; 156cabdff1aSopenharmony_ci st->codecpar->sample_rate = 48000; 157cabdff1aSopenharmony_ci st->codecpar->bit_rate = 2 * 1 * 48000 * 8; 158cabdff1aSopenharmony_ci st->codecpar->block_align = 2 * 1; 159cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample = 16; 160cabdff1aSopenharmony_ci break; 161cabdff1aSopenharmony_ci case 17: 162cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 163cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_AC3; 164cabdff1aSopenharmony_ci st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; 165cabdff1aSopenharmony_ci st->codecpar->sample_rate = 48000; 166cabdff1aSopenharmony_ci break; 167cabdff1aSopenharmony_ci case 26: /* AVCi50 / AVCi100 (AVC Intra) */ 168cabdff1aSopenharmony_ci case 29: /* AVCHD */ 169cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 170cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_H264; 171cabdff1aSopenharmony_ci sti->need_parsing = AVSTREAM_PARSE_HEADERS; 172cabdff1aSopenharmony_ci break; 173cabdff1aSopenharmony_ci // timecode tracks: 174cabdff1aSopenharmony_ci case 7: 175cabdff1aSopenharmony_ci case 8: 176cabdff1aSopenharmony_ci case 24: 177cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_DATA; 178cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_NONE; 179cabdff1aSopenharmony_ci break; 180cabdff1aSopenharmony_ci case 30: 181cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 182cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_DNXHD; 183cabdff1aSopenharmony_ci break; 184cabdff1aSopenharmony_ci default: 185cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN; 186cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_NONE; 187cabdff1aSopenharmony_ci break; 188cabdff1aSopenharmony_ci } 189cabdff1aSopenharmony_ci return s->nb_streams - 1; 190cabdff1aSopenharmony_ci} 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci/** 193cabdff1aSopenharmony_ci * @brief filters out interesting tags from material information. 194cabdff1aSopenharmony_ci * @param len length of tag section, will be adjusted to contain remaining bytes 195cabdff1aSopenharmony_ci * @param si struct to store collected information into 196cabdff1aSopenharmony_ci */ 197cabdff1aSopenharmony_cistatic void gxf_material_tags(AVIOContext *pb, int *len, struct gxf_stream_info *si) { 198cabdff1aSopenharmony_ci si->first_field = AV_NOPTS_VALUE; 199cabdff1aSopenharmony_ci si->last_field = AV_NOPTS_VALUE; 200cabdff1aSopenharmony_ci while (*len >= 2) { 201cabdff1aSopenharmony_ci GXFMatTag tag = avio_r8(pb); 202cabdff1aSopenharmony_ci int tlen = avio_r8(pb); 203cabdff1aSopenharmony_ci *len -= 2; 204cabdff1aSopenharmony_ci if (tlen > *len) 205cabdff1aSopenharmony_ci return; 206cabdff1aSopenharmony_ci *len -= tlen; 207cabdff1aSopenharmony_ci if (tlen == 4) { 208cabdff1aSopenharmony_ci uint32_t value = avio_rb32(pb); 209cabdff1aSopenharmony_ci if (tag == MAT_FIRST_FIELD) 210cabdff1aSopenharmony_ci si->first_field = value; 211cabdff1aSopenharmony_ci else if (tag == MAT_LAST_FIELD) 212cabdff1aSopenharmony_ci si->last_field = value; 213cabdff1aSopenharmony_ci } else 214cabdff1aSopenharmony_ci avio_skip(pb, tlen); 215cabdff1aSopenharmony_ci } 216cabdff1aSopenharmony_ci} 217cabdff1aSopenharmony_ci 218cabdff1aSopenharmony_cistatic const AVRational frame_rate_tab[] = { 219cabdff1aSopenharmony_ci { 60, 1}, 220cabdff1aSopenharmony_ci {60000, 1001}, 221cabdff1aSopenharmony_ci { 50, 1}, 222cabdff1aSopenharmony_ci { 30, 1}, 223cabdff1aSopenharmony_ci {30000, 1001}, 224cabdff1aSopenharmony_ci { 25, 1}, 225cabdff1aSopenharmony_ci { 24, 1}, 226cabdff1aSopenharmony_ci {24000, 1001}, 227cabdff1aSopenharmony_ci { 0, 0}, 228cabdff1aSopenharmony_ci}; 229cabdff1aSopenharmony_ci 230cabdff1aSopenharmony_ci/** 231cabdff1aSopenharmony_ci * @brief convert fps tag value to AVRational fps 232cabdff1aSopenharmony_ci * @param fps fps value from tag 233cabdff1aSopenharmony_ci * @return fps as AVRational, or 0 / 0 if unknown 234cabdff1aSopenharmony_ci */ 235cabdff1aSopenharmony_cistatic AVRational fps_tag2avr(int32_t fps) { 236cabdff1aSopenharmony_ci if (fps < 1 || fps > 9) fps = 9; 237cabdff1aSopenharmony_ci return frame_rate_tab[fps - 1]; 238cabdff1aSopenharmony_ci} 239cabdff1aSopenharmony_ci 240cabdff1aSopenharmony_ci/** 241cabdff1aSopenharmony_ci * @brief convert UMF attributes flags to AVRational fps 242cabdff1aSopenharmony_ci * @param flags UMF flags to convert 243cabdff1aSopenharmony_ci * @return fps as AVRational, or 0 / 0 if unknown 244cabdff1aSopenharmony_ci */ 245cabdff1aSopenharmony_cistatic AVRational fps_umf2avr(uint32_t flags) { 246cabdff1aSopenharmony_ci static const AVRational map[] = {{50, 1}, {60000, 1001}, {24, 1}, 247cabdff1aSopenharmony_ci {25, 1}, {30000, 1001}}; 248cabdff1aSopenharmony_ci int idx = av_log2((flags & 0x7c0) >> 6); 249cabdff1aSopenharmony_ci return map[idx]; 250cabdff1aSopenharmony_ci} 251cabdff1aSopenharmony_ci 252cabdff1aSopenharmony_ci/** 253cabdff1aSopenharmony_ci * @brief filters out interesting tags from track information. 254cabdff1aSopenharmony_ci * @param len length of tag section, will be adjusted to contain remaining bytes 255cabdff1aSopenharmony_ci * @param si struct to store collected information into 256cabdff1aSopenharmony_ci */ 257cabdff1aSopenharmony_cistatic void gxf_track_tags(AVIOContext *pb, int *len, struct gxf_stream_info *si) { 258cabdff1aSopenharmony_ci si->frames_per_second = (AVRational){0, 0}; 259cabdff1aSopenharmony_ci si->fields_per_frame = 0; 260cabdff1aSopenharmony_ci si->track_aux_data = 0x80000000; 261cabdff1aSopenharmony_ci while (*len >= 2) { 262cabdff1aSopenharmony_ci GXFTrackTag tag = avio_r8(pb); 263cabdff1aSopenharmony_ci int tlen = avio_r8(pb); 264cabdff1aSopenharmony_ci *len -= 2; 265cabdff1aSopenharmony_ci if (tlen > *len) 266cabdff1aSopenharmony_ci return; 267cabdff1aSopenharmony_ci *len -= tlen; 268cabdff1aSopenharmony_ci if (tlen == 4) { 269cabdff1aSopenharmony_ci uint32_t value = avio_rb32(pb); 270cabdff1aSopenharmony_ci if (tag == TRACK_FPS) 271cabdff1aSopenharmony_ci si->frames_per_second = fps_tag2avr(value); 272cabdff1aSopenharmony_ci else if (tag == TRACK_FPF && (value == 1 || value == 2)) 273cabdff1aSopenharmony_ci si->fields_per_frame = value; 274cabdff1aSopenharmony_ci } else if (tlen == 8 && tag == TRACK_AUX) 275cabdff1aSopenharmony_ci si->track_aux_data = avio_rl64(pb); 276cabdff1aSopenharmony_ci else 277cabdff1aSopenharmony_ci avio_skip(pb, tlen); 278cabdff1aSopenharmony_ci } 279cabdff1aSopenharmony_ci} 280cabdff1aSopenharmony_ci 281cabdff1aSopenharmony_ci/** 282cabdff1aSopenharmony_ci * @brief read index from FLT packet into stream 0 av_index 283cabdff1aSopenharmony_ci */ 284cabdff1aSopenharmony_cistatic void gxf_read_index(AVFormatContext *s, int pkt_len) { 285cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 286cabdff1aSopenharmony_ci AVStream *st; 287cabdff1aSopenharmony_ci uint32_t fields_per_map, map_cnt; 288cabdff1aSopenharmony_ci int i; 289cabdff1aSopenharmony_ci if (pkt_len < 8) 290cabdff1aSopenharmony_ci return; 291cabdff1aSopenharmony_ci fields_per_map = avio_rl32(pb); 292cabdff1aSopenharmony_ci map_cnt = avio_rl32(pb); 293cabdff1aSopenharmony_ci pkt_len -= 8; 294cabdff1aSopenharmony_ci if ((s->flags & AVFMT_FLAG_IGNIDX) || !s->streams) { 295cabdff1aSopenharmony_ci avio_skip(pb, pkt_len); 296cabdff1aSopenharmony_ci return; 297cabdff1aSopenharmony_ci } 298cabdff1aSopenharmony_ci st = s->streams[0]; 299cabdff1aSopenharmony_ci if (map_cnt > 1000) { 300cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 301cabdff1aSopenharmony_ci "too many index entries %"PRIu32" (%"PRIx32")\n", 302cabdff1aSopenharmony_ci map_cnt, map_cnt); 303cabdff1aSopenharmony_ci map_cnt = 1000; 304cabdff1aSopenharmony_ci } 305cabdff1aSopenharmony_ci if (pkt_len < 4 * map_cnt) { 306cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "invalid index length\n"); 307cabdff1aSopenharmony_ci avio_skip(pb, pkt_len); 308cabdff1aSopenharmony_ci return; 309cabdff1aSopenharmony_ci } 310cabdff1aSopenharmony_ci pkt_len -= 4 * map_cnt; 311cabdff1aSopenharmony_ci av_add_index_entry(st, 0, 0, 0, 0, 0); 312cabdff1aSopenharmony_ci for (i = 0; i < map_cnt; i++) 313cabdff1aSopenharmony_ci av_add_index_entry(st, (uint64_t)avio_rl32(pb) * 1024, 314cabdff1aSopenharmony_ci i * (uint64_t)fields_per_map + 1, 0, 0, 0); 315cabdff1aSopenharmony_ci avio_skip(pb, pkt_len); 316cabdff1aSopenharmony_ci} 317cabdff1aSopenharmony_ci 318cabdff1aSopenharmony_cistatic int gxf_header(AVFormatContext *s) { 319cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 320cabdff1aSopenharmony_ci GXFPktType pkt_type; 321cabdff1aSopenharmony_ci int map_len; 322cabdff1aSopenharmony_ci int len; 323cabdff1aSopenharmony_ci AVRational main_timebase = {0, 0}; 324cabdff1aSopenharmony_ci struct gxf_stream_info *si = s->priv_data; 325cabdff1aSopenharmony_ci int i; 326cabdff1aSopenharmony_ci if (!parse_packet_header(pb, &pkt_type, &map_len) || pkt_type != PKT_MAP) { 327cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "map packet not found\n"); 328cabdff1aSopenharmony_ci return 0; 329cabdff1aSopenharmony_ci } 330cabdff1aSopenharmony_ci map_len -= 2; 331cabdff1aSopenharmony_ci if (avio_r8(pb) != 0x0e0 || avio_r8(pb) != 0xff) { 332cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "unknown version or invalid map preamble\n"); 333cabdff1aSopenharmony_ci return 0; 334cabdff1aSopenharmony_ci } 335cabdff1aSopenharmony_ci map_len -= 2; 336cabdff1aSopenharmony_ci len = avio_rb16(pb); // length of material data section 337cabdff1aSopenharmony_ci if (len > map_len) { 338cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "material data longer than map data\n"); 339cabdff1aSopenharmony_ci return 0; 340cabdff1aSopenharmony_ci } 341cabdff1aSopenharmony_ci map_len -= len; 342cabdff1aSopenharmony_ci gxf_material_tags(pb, &len, si); 343cabdff1aSopenharmony_ci avio_skip(pb, len); 344cabdff1aSopenharmony_ci map_len -= 2; 345cabdff1aSopenharmony_ci len = avio_rb16(pb); // length of track description 346cabdff1aSopenharmony_ci if (len > map_len) { 347cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "track description longer than map data\n"); 348cabdff1aSopenharmony_ci return 0; 349cabdff1aSopenharmony_ci } 350cabdff1aSopenharmony_ci map_len -= len; 351cabdff1aSopenharmony_ci while (len > 0) { 352cabdff1aSopenharmony_ci int track_type, track_id, track_len; 353cabdff1aSopenharmony_ci AVStream *st; 354cabdff1aSopenharmony_ci int idx; 355cabdff1aSopenharmony_ci len -= 4; 356cabdff1aSopenharmony_ci track_type = avio_r8(pb); 357cabdff1aSopenharmony_ci track_id = avio_r8(pb); 358cabdff1aSopenharmony_ci track_len = avio_rb16(pb); 359cabdff1aSopenharmony_ci len -= track_len; 360cabdff1aSopenharmony_ci if (!(track_type & 0x80)) { 361cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "invalid track type %x\n", track_type); 362cabdff1aSopenharmony_ci continue; 363cabdff1aSopenharmony_ci } 364cabdff1aSopenharmony_ci track_type &= 0x7f; 365cabdff1aSopenharmony_ci if ((track_id & 0xc0) != 0xc0) { 366cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "invalid track id %x\n", track_id); 367cabdff1aSopenharmony_ci continue; 368cabdff1aSopenharmony_ci } 369cabdff1aSopenharmony_ci track_id &= 0x3f; 370cabdff1aSopenharmony_ci gxf_track_tags(pb, &track_len, si); 371cabdff1aSopenharmony_ci // check for timecode tracks 372cabdff1aSopenharmony_ci if (track_type == 7 || track_type == 8 || track_type == 24) { 373cabdff1aSopenharmony_ci add_timecode_metadata(&s->metadata, "timecode", 374cabdff1aSopenharmony_ci si->track_aux_data & 0xffffffff, 375cabdff1aSopenharmony_ci si->fields_per_frame); 376cabdff1aSopenharmony_ci 377cabdff1aSopenharmony_ci } 378cabdff1aSopenharmony_ci avio_skip(pb, track_len); 379cabdff1aSopenharmony_ci 380cabdff1aSopenharmony_ci idx = get_sindex(s, track_id, track_type); 381cabdff1aSopenharmony_ci if (idx < 0) continue; 382cabdff1aSopenharmony_ci st = s->streams[idx]; 383cabdff1aSopenharmony_ci if (!main_timebase.num || !main_timebase.den) { 384cabdff1aSopenharmony_ci main_timebase.num = si->frames_per_second.den; 385cabdff1aSopenharmony_ci main_timebase.den = si->frames_per_second.num * 2; 386cabdff1aSopenharmony_ci } 387cabdff1aSopenharmony_ci st->start_time = si->first_field; 388cabdff1aSopenharmony_ci if (si->first_field != AV_NOPTS_VALUE && si->last_field != AV_NOPTS_VALUE) 389cabdff1aSopenharmony_ci st->duration = si->last_field - si->first_field; 390cabdff1aSopenharmony_ci } 391cabdff1aSopenharmony_ci if (len < 0) 392cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "invalid track description length specified\n"); 393cabdff1aSopenharmony_ci if (map_len) 394cabdff1aSopenharmony_ci avio_skip(pb, map_len); 395cabdff1aSopenharmony_ci if (!parse_packet_header(pb, &pkt_type, &len)) { 396cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "sync lost in header\n"); 397cabdff1aSopenharmony_ci return -1; 398cabdff1aSopenharmony_ci } 399cabdff1aSopenharmony_ci if (pkt_type == PKT_FLT) { 400cabdff1aSopenharmony_ci gxf_read_index(s, len); 401cabdff1aSopenharmony_ci if (!parse_packet_header(pb, &pkt_type, &len)) { 402cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "sync lost in header\n"); 403cabdff1aSopenharmony_ci return -1; 404cabdff1aSopenharmony_ci } 405cabdff1aSopenharmony_ci } 406cabdff1aSopenharmony_ci if (pkt_type == PKT_UMF) { 407cabdff1aSopenharmony_ci if (len >= 0x39) { 408cabdff1aSopenharmony_ci AVRational fps; 409cabdff1aSopenharmony_ci len -= 0x39; 410cabdff1aSopenharmony_ci avio_skip(pb, 5); // preamble 411cabdff1aSopenharmony_ci avio_skip(pb, 0x30); // payload description 412cabdff1aSopenharmony_ci fps = fps_umf2avr(avio_rl32(pb)); 413cabdff1aSopenharmony_ci if (!main_timebase.num || !main_timebase.den) { 414cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "No FPS track tag, using UMF fps tag." 415cabdff1aSopenharmony_ci " This might give wrong results.\n"); 416cabdff1aSopenharmony_ci // this may not always be correct, but simply the best we can get 417cabdff1aSopenharmony_ci main_timebase.num = fps.den; 418cabdff1aSopenharmony_ci main_timebase.den = fps.num * 2; 419cabdff1aSopenharmony_ci } 420cabdff1aSopenharmony_ci 421cabdff1aSopenharmony_ci if (len >= 0x18) { 422cabdff1aSopenharmony_ci len -= 0x18; 423cabdff1aSopenharmony_ci avio_skip(pb, 0x10); 424cabdff1aSopenharmony_ci add_timecode_metadata(&s->metadata, "timecode_at_mark_in", 425cabdff1aSopenharmony_ci avio_rl32(pb), si->fields_per_frame); 426cabdff1aSopenharmony_ci add_timecode_metadata(&s->metadata, "timecode_at_mark_out", 427cabdff1aSopenharmony_ci avio_rl32(pb), si->fields_per_frame); 428cabdff1aSopenharmony_ci } 429cabdff1aSopenharmony_ci } else 430cabdff1aSopenharmony_ci av_log(s, AV_LOG_INFO, "UMF packet too short\n"); 431cabdff1aSopenharmony_ci } else 432cabdff1aSopenharmony_ci av_log(s, AV_LOG_INFO, "UMF packet missing\n"); 433cabdff1aSopenharmony_ci avio_skip(pb, len); 434cabdff1aSopenharmony_ci // set a fallback value, 60000/1001 is specified for audio-only files 435cabdff1aSopenharmony_ci // so use that regardless of why we do not know the video frame rate. 436cabdff1aSopenharmony_ci if (!main_timebase.num || !main_timebase.den) 437cabdff1aSopenharmony_ci main_timebase = (AVRational){1001, 60000}; 438cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 439cabdff1aSopenharmony_ci AVStream *st = s->streams[i]; 440cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 32, main_timebase.num, main_timebase.den); 441cabdff1aSopenharmony_ci } 442cabdff1aSopenharmony_ci return 0; 443cabdff1aSopenharmony_ci} 444cabdff1aSopenharmony_ci 445cabdff1aSopenharmony_ci#define READ_ONE() \ 446cabdff1aSopenharmony_ci { \ 447cabdff1aSopenharmony_ci if (!max_interval-- || avio_feof(pb)) \ 448cabdff1aSopenharmony_ci goto out; \ 449cabdff1aSopenharmony_ci tmp = tmp << 8 | avio_r8(pb); \ 450cabdff1aSopenharmony_ci } 451cabdff1aSopenharmony_ci 452cabdff1aSopenharmony_ci/** 453cabdff1aSopenharmony_ci * @brief resync the stream on the next media packet with specified properties 454cabdff1aSopenharmony_ci * @param max_interval how many bytes to search for matching packet at most 455cabdff1aSopenharmony_ci * @param track track id the media packet must belong to, -1 for any 456cabdff1aSopenharmony_ci * @param timestamp minimum timestamp (== field number) the packet must have, -1 for any 457cabdff1aSopenharmony_ci * @return timestamp of packet found 458cabdff1aSopenharmony_ci */ 459cabdff1aSopenharmony_cistatic int64_t gxf_resync_media(AVFormatContext *s, uint64_t max_interval, int track, int timestamp) { 460cabdff1aSopenharmony_ci uint32_t tmp; 461cabdff1aSopenharmony_ci uint64_t last_pos; 462cabdff1aSopenharmony_ci uint64_t last_found_pos = 0; 463cabdff1aSopenharmony_ci int cur_track; 464cabdff1aSopenharmony_ci int64_t cur_timestamp = AV_NOPTS_VALUE; 465cabdff1aSopenharmony_ci int len; 466cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 467cabdff1aSopenharmony_ci GXFPktType type; 468cabdff1aSopenharmony_ci tmp = avio_rb32(pb); 469cabdff1aSopenharmony_cistart: 470cabdff1aSopenharmony_ci while (tmp) 471cabdff1aSopenharmony_ci READ_ONE(); 472cabdff1aSopenharmony_ci READ_ONE(); 473cabdff1aSopenharmony_ci if (tmp != 1) 474cabdff1aSopenharmony_ci goto start; 475cabdff1aSopenharmony_ci last_pos = avio_tell(pb); 476cabdff1aSopenharmony_ci if (avio_seek(pb, -5, SEEK_CUR) < 0) 477cabdff1aSopenharmony_ci goto out; 478cabdff1aSopenharmony_ci if (!parse_packet_header(pb, &type, &len) || type != PKT_MEDIA) { 479cabdff1aSopenharmony_ci if (avio_seek(pb, last_pos, SEEK_SET) < 0) 480cabdff1aSopenharmony_ci goto out; 481cabdff1aSopenharmony_ci goto start; 482cabdff1aSopenharmony_ci } 483cabdff1aSopenharmony_ci avio_r8(pb); 484cabdff1aSopenharmony_ci cur_track = avio_r8(pb); 485cabdff1aSopenharmony_ci cur_timestamp = avio_rb32(pb); 486cabdff1aSopenharmony_ci last_found_pos = avio_tell(pb) - 16 - 6; 487cabdff1aSopenharmony_ci if ((track >= 0 && track != cur_track) || (timestamp >= 0 && timestamp > cur_timestamp)) { 488cabdff1aSopenharmony_ci if (avio_seek(pb, last_pos, SEEK_SET) >= 0) 489cabdff1aSopenharmony_ci goto start; 490cabdff1aSopenharmony_ci } 491cabdff1aSopenharmony_ciout: 492cabdff1aSopenharmony_ci if (last_found_pos) 493cabdff1aSopenharmony_ci avio_seek(pb, last_found_pos, SEEK_SET); 494cabdff1aSopenharmony_ci return cur_timestamp; 495cabdff1aSopenharmony_ci} 496cabdff1aSopenharmony_ci 497cabdff1aSopenharmony_cistatic int gxf_packet(AVFormatContext *s, AVPacket *pkt) { 498cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 499cabdff1aSopenharmony_ci GXFPktType pkt_type; 500cabdff1aSopenharmony_ci int pkt_len; 501cabdff1aSopenharmony_ci struct gxf_stream_info *si = s->priv_data; 502cabdff1aSopenharmony_ci 503cabdff1aSopenharmony_ci while (!pb->eof_reached) { 504cabdff1aSopenharmony_ci AVStream *st; 505cabdff1aSopenharmony_ci int track_type, track_id, ret; 506cabdff1aSopenharmony_ci int field_nr, field_info, skip = 0; 507cabdff1aSopenharmony_ci int stream_index; 508cabdff1aSopenharmony_ci if (!parse_packet_header(pb, &pkt_type, &pkt_len)) { 509cabdff1aSopenharmony_ci if (!avio_feof(pb)) 510cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "sync lost\n"); 511cabdff1aSopenharmony_ci return -1; 512cabdff1aSopenharmony_ci } 513cabdff1aSopenharmony_ci if (pkt_type == PKT_FLT) { 514cabdff1aSopenharmony_ci gxf_read_index(s, pkt_len); 515cabdff1aSopenharmony_ci continue; 516cabdff1aSopenharmony_ci } 517cabdff1aSopenharmony_ci if (pkt_type != PKT_MEDIA) { 518cabdff1aSopenharmony_ci avio_skip(pb, pkt_len); 519cabdff1aSopenharmony_ci continue; 520cabdff1aSopenharmony_ci } 521cabdff1aSopenharmony_ci if (pkt_len < 16) { 522cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "invalid media packet length\n"); 523cabdff1aSopenharmony_ci continue; 524cabdff1aSopenharmony_ci } 525cabdff1aSopenharmony_ci pkt_len -= 16; 526cabdff1aSopenharmony_ci track_type = avio_r8(pb); 527cabdff1aSopenharmony_ci track_id = avio_r8(pb); 528cabdff1aSopenharmony_ci stream_index = get_sindex(s, track_id, track_type); 529cabdff1aSopenharmony_ci if (stream_index < 0) 530cabdff1aSopenharmony_ci return stream_index; 531cabdff1aSopenharmony_ci st = s->streams[stream_index]; 532cabdff1aSopenharmony_ci field_nr = avio_rb32(pb); 533cabdff1aSopenharmony_ci field_info = avio_rb32(pb); 534cabdff1aSopenharmony_ci avio_rb32(pb); // "timeline" field number 535cabdff1aSopenharmony_ci avio_r8(pb); // flags 536cabdff1aSopenharmony_ci avio_r8(pb); // reserved 537cabdff1aSopenharmony_ci if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S24LE || 538cabdff1aSopenharmony_ci st->codecpar->codec_id == AV_CODEC_ID_PCM_S16LE) { 539cabdff1aSopenharmony_ci int first = field_info >> 16; 540cabdff1aSopenharmony_ci int last = field_info & 0xffff; // last is exclusive 541cabdff1aSopenharmony_ci int bps = av_get_bits_per_sample(st->codecpar->codec_id)>>3; 542cabdff1aSopenharmony_ci if (first <= last && last*bps <= pkt_len) { 543cabdff1aSopenharmony_ci avio_skip(pb, first*bps); 544cabdff1aSopenharmony_ci skip = pkt_len - last*bps; 545cabdff1aSopenharmony_ci pkt_len = (last-first)*bps; 546cabdff1aSopenharmony_ci } else 547cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "invalid first and last sample values\n"); 548cabdff1aSopenharmony_ci } 549cabdff1aSopenharmony_ci ret = av_get_packet(pb, pkt, pkt_len); 550cabdff1aSopenharmony_ci if (skip) 551cabdff1aSopenharmony_ci avio_skip(pb, skip); 552cabdff1aSopenharmony_ci pkt->stream_index = stream_index; 553cabdff1aSopenharmony_ci pkt->dts = field_nr; 554cabdff1aSopenharmony_ci 555cabdff1aSopenharmony_ci //set duration manually for DV or else lavf misdetects the frame rate 556cabdff1aSopenharmony_ci if (st->codecpar->codec_id == AV_CODEC_ID_DVVIDEO) 557cabdff1aSopenharmony_ci pkt->duration = si->fields_per_frame; 558cabdff1aSopenharmony_ci 559cabdff1aSopenharmony_ci return ret; 560cabdff1aSopenharmony_ci } 561cabdff1aSopenharmony_ci return AVERROR_EOF; 562cabdff1aSopenharmony_ci} 563cabdff1aSopenharmony_ci 564cabdff1aSopenharmony_cistatic int gxf_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { 565cabdff1aSopenharmony_ci int64_t res = 0; 566cabdff1aSopenharmony_ci uint64_t pos; 567cabdff1aSopenharmony_ci uint64_t maxlen = 100 * 1024 * 1024; 568cabdff1aSopenharmony_ci AVStream *st = s->streams[0]; 569cabdff1aSopenharmony_ci FFStream *const sti = ffstream(st); 570cabdff1aSopenharmony_ci int64_t start_time = s->streams[stream_index]->start_time; 571cabdff1aSopenharmony_ci int64_t found; 572cabdff1aSopenharmony_ci int idx; 573cabdff1aSopenharmony_ci if (timestamp < start_time) timestamp = start_time; 574cabdff1aSopenharmony_ci idx = av_index_search_timestamp(st, timestamp - start_time, 575cabdff1aSopenharmony_ci AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD); 576cabdff1aSopenharmony_ci if (idx < 0) 577cabdff1aSopenharmony_ci return -1; 578cabdff1aSopenharmony_ci pos = sti->index_entries[idx].pos; 579cabdff1aSopenharmony_ci if (idx < sti->nb_index_entries - 2) 580cabdff1aSopenharmony_ci maxlen = sti->index_entries[idx + 2].pos - pos; 581cabdff1aSopenharmony_ci maxlen = FFMAX(maxlen, 200 * 1024); 582cabdff1aSopenharmony_ci res = avio_seek(s->pb, pos, SEEK_SET); 583cabdff1aSopenharmony_ci if (res < 0) 584cabdff1aSopenharmony_ci return res; 585cabdff1aSopenharmony_ci found = gxf_resync_media(s, maxlen, -1, timestamp); 586cabdff1aSopenharmony_ci if (FFABS(found - timestamp) > 4) 587cabdff1aSopenharmony_ci return -1; 588cabdff1aSopenharmony_ci return 0; 589cabdff1aSopenharmony_ci} 590cabdff1aSopenharmony_ci 591cabdff1aSopenharmony_cistatic int64_t gxf_read_timestamp(AVFormatContext *s, int stream_index, 592cabdff1aSopenharmony_ci int64_t *pos, int64_t pos_limit) { 593cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 594cabdff1aSopenharmony_ci int64_t res; 595cabdff1aSopenharmony_ci if (avio_seek(pb, *pos, SEEK_SET) < 0) 596cabdff1aSopenharmony_ci return AV_NOPTS_VALUE; 597cabdff1aSopenharmony_ci res = gxf_resync_media(s, pos_limit - *pos, -1, -1); 598cabdff1aSopenharmony_ci *pos = avio_tell(pb); 599cabdff1aSopenharmony_ci return res; 600cabdff1aSopenharmony_ci} 601cabdff1aSopenharmony_ci 602cabdff1aSopenharmony_ciconst AVInputFormat ff_gxf_demuxer = { 603cabdff1aSopenharmony_ci .name = "gxf", 604cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("GXF (General eXchange Format)"), 605cabdff1aSopenharmony_ci .priv_data_size = sizeof(struct gxf_stream_info), 606cabdff1aSopenharmony_ci .read_probe = gxf_probe, 607cabdff1aSopenharmony_ci .read_header = gxf_header, 608cabdff1aSopenharmony_ci .read_packet = gxf_packet, 609cabdff1aSopenharmony_ci .read_seek = gxf_seek, 610cabdff1aSopenharmony_ci .read_timestamp = gxf_read_timestamp, 611cabdff1aSopenharmony_ci}; 612