📄 gxf.c
字号:
/* * GXF demuxer. * Copyright (c) 2006 Reimar Doeffinger. * * 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 "avformat.h"#include "common.h"#include "gxf.h"typedef struct { int64_t first_field; int64_t last_field; AVRational frames_per_second; int32_t fields_per_frame;} st_info_t;/** * \brief parses a packet header, extracting type and length * \param pb ByteIOContext to read header from * \param type detected packet type is stored here * \param length detected packet length, excluding header is stored here * \return 0 if header not found or contains invalid data, 1 otherwise */static int parse_packet_header(ByteIOContext *pb, pkt_type_t *type, int *length) { if (get_be32(pb)) return 0; if (get_byte(pb) != 1) return 0; *type = get_byte(pb); *length = get_be32(pb); if ((*length >> 24) || *length < 16) return 0; *length -= 16; if (get_be32(pb)) return 0; if (get_byte(pb) != 0xe1) return 0; if (get_byte(pb) != 0xe2) return 0; return 1;}/** * \brief check if file starts with a PKT_MAP header */static int gxf_probe(AVProbeData *p) { static const uint8_t startcode[] = {0, 0, 0, 0, 1, 0xbc}; // start with map packet static const uint8_t endcode[] = {0, 0, 0, 0, 0xe1, 0xe2}; if (!memcmp(p->buf, startcode, sizeof(startcode)) && !memcmp(&p->buf[16 - sizeof(endcode)], endcode, sizeof(endcode))) return AVPROBE_SCORE_MAX; return 0;}/** * \brief gets the stream index for the track with the specified id, creates new * stream if not found * \param stream id of stream to find / add * \param format stream format identifier */static int get_sindex(AVFormatContext *s, int id, int format) { int i; AVStream *st = NULL; for (i = 0; i < s->nb_streams; i++) { if (s->streams[i]->id == id) return i; } st = av_new_stream(s, id); switch (format) { case 3: case 4: st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_MJPEG; break; case 13: case 15: st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_DVVIDEO; break; case 14: case 16: st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_DVVIDEO; break; case 11: case 12: case 20: st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_MPEG2VIDEO; st->need_parsing = AVSTREAM_PARSE_HEADERS; //get keyframe flag etc. break; case 22: case 23: st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_MPEG1VIDEO; st->need_parsing = AVSTREAM_PARSE_HEADERS; //get keyframe flag etc. break; case 9: st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_PCM_S24LE; st->codec->channels = 1; st->codec->sample_rate = 48000; st->codec->bit_rate = 3 * 1 * 48000 * 8; st->codec->block_align = 3 * 1; st->codec->bits_per_sample = 24; break; case 10: st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_PCM_S16LE; st->codec->channels = 1; st->codec->sample_rate = 48000; st->codec->bit_rate = 2 * 1 * 48000 * 8; st->codec->block_align = 2 * 1; st->codec->bits_per_sample = 16; break; case 17: st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_AC3; st->codec->channels = 2; st->codec->sample_rate = 48000; break; // timecode tracks: case 7: case 8: case 24: st->codec->codec_type = CODEC_TYPE_DATA; st->codec->codec_id = CODEC_ID_NONE; break; default: st->codec->codec_type = CODEC_TYPE_UNKNOWN; st->codec->codec_id = CODEC_ID_NONE; break; } return s->nb_streams - 1;}/** * \brief filters out interesting tags from material information. * \param len length of tag section, will be adjusted to contain remaining bytes * \param si struct to store collected information into */static void gxf_material_tags(ByteIOContext *pb, int *len, st_info_t *si) { si->first_field = AV_NOPTS_VALUE; si->last_field = AV_NOPTS_VALUE; while (*len >= 2) { mat_tag_t tag = get_byte(pb); int tlen = get_byte(pb); *len -= 2; if (tlen > *len) return; *len -= tlen; if (tlen == 4) { uint32_t value = get_be32(pb); if (tag == MAT_FIRST_FIELD) si->first_field = value; else if (tag == MAT_LAST_FIELD) si->last_field = value; } else url_fskip(pb, tlen); }}/** * \brief convert fps tag value to AVRational fps * \param fps fps value from tag * \return fps as AVRational, or 0 / 0 if unknown */static AVRational fps_tag2avr(int32_t fps) { extern const AVRational ff_frame_rate_tab[]; if (fps < 1 || fps > 9) fps = 9; return ff_frame_rate_tab[9 - fps]; // values have opposite order}/** * \brief convert UMF attributes flags to AVRational fps * \param fps fps value from flags * \return fps as AVRational, or 0 / 0 if unknown */static AVRational fps_umf2avr(uint32_t flags) { static const AVRational map[] = {{50, 1}, {60000, 1001}, {24, 1}, {25, 1}, {30000, 1001}}; int idx = av_log2((flags & 0x7c0) >> 6); return map[idx];}/** * \brief filters out interesting tags from track information. * \param len length of tag section, will be adjusted to contain remaining bytes * \param si struct to store collected information into */static void gxf_track_tags(ByteIOContext *pb, int *len, st_info_t *si) { si->frames_per_second = (AVRational){0, 0}; si->fields_per_frame = 0; while (*len >= 2) { track_tag_t tag = get_byte(pb); int tlen = get_byte(pb); *len -= 2; if (tlen > *len) return; *len -= tlen; if (tlen == 4) { uint32_t value = get_be32(pb); if (tag == TRACK_FPS) si->frames_per_second = fps_tag2avr(value); else if (tag == TRACK_FPF && (value == 1 || value == 2)) si->fields_per_frame = value; } else url_fskip(pb, tlen); }}/** * \brief read index from FLT packet into stream 0 av_index */static void gxf_read_index(AVFormatContext *s, int pkt_len) { ByteIOContext *pb = &s->pb; AVStream *st = s->streams[0]; uint32_t fields_per_map = get_le32(pb); uint32_t map_cnt = get_le32(pb); int i; pkt_len -= 8; if (map_cnt > 1000) { av_log(s, AV_LOG_ERROR, "GXF: too many index entries %u (%x)\n", map_cnt, map_cnt); map_cnt = 1000; } if (pkt_len < 4 * map_cnt) { av_log(s, AV_LOG_ERROR, "GXF: invalid index length\n"); url_fskip(pb, pkt_len); return; } pkt_len -= 4 * map_cnt; av_add_index_entry(st, 0, 0, 0, 0, 0); for (i = 0; i < map_cnt; i++) av_add_index_entry(st, (uint64_t)get_le32(pb) * 1024,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -