📄 matroska.c
字号:
static intmatroska_ebmlnum_sint (uint8_t *data, uint32_t size, int64_t *num){ uint64_t unum; int res; /* read as unsigned number first */ if ((res = matroska_ebmlnum_uint(data, size, &unum)) < 0) return res; /* make signed (weird way) */ if (unum == (uint64_t)-1) *num = INT64_MAX; else *num = unum - ((1LL << ((7 * res) - 1)) - 1); return res;}/* * Read an EBML header. * 0 is success, < 0 is failure. */static intebml_read_header (MatroskaDemuxContext *matroska, char **doctype, int *version){ uint32_t id; int level_up, res = 0; /* default init */ if (doctype) *doctype = NULL; if (version) *version = 1; if (!(id = ebml_peek_id(matroska, &level_up)) || level_up != 0 || id != EBML_ID_HEADER) { av_log(matroska->ctx, AV_LOG_ERROR, "This is not an EBML file (id=0x%x/0x%x)\n", id, EBML_ID_HEADER); return AVERROR_INVALIDDATA; } if ((res = ebml_read_master(matroska, &id)) < 0) return res; while (res == 0) { if (!(id = ebml_peek_id(matroska, &level_up))) return AVERROR_IO; /* end-of-header */ if (level_up) break; switch (id) { /* is our read version uptodate? */ case EBML_ID_EBMLREADVERSION: { uint64_t num; if ((res = ebml_read_uint(matroska, &id, &num)) < 0) return res; if (num > EBML_VERSION) { av_log(matroska->ctx, AV_LOG_ERROR, "EBML version %"PRIu64" (> %d) is not supported\n", num, EBML_VERSION); return AVERROR_INVALIDDATA; } break; } /* we only handle 8 byte lengths at max */ case EBML_ID_EBMLMAXSIZELENGTH: { uint64_t num; if ((res = ebml_read_uint(matroska, &id, &num)) < 0) return res; if (num > sizeof(uint64_t)) { av_log(matroska->ctx, AV_LOG_ERROR, "Integers of size %"PRIu64" (> %zd) not supported\n", num, sizeof(uint64_t)); return AVERROR_INVALIDDATA; } break; } /* we handle 4 byte IDs at max */ case EBML_ID_EBMLMAXIDLENGTH: { uint64_t num; if ((res = ebml_read_uint(matroska, &id, &num)) < 0) return res; if (num > sizeof(uint32_t)) { av_log(matroska->ctx, AV_LOG_ERROR, "IDs of size %"PRIu64" (> %zu) not supported\n", num, sizeof(uint32_t)); return AVERROR_INVALIDDATA; } break; } case EBML_ID_DOCTYPE: { char *text; if ((res = ebml_read_ascii(matroska, &id, &text)) < 0) return res; if (doctype) { if (*doctype) av_free(*doctype); *doctype = text; } else av_free(text); break; } case EBML_ID_DOCTYPEREADVERSION: { uint64_t num; if ((res = ebml_read_uint(matroska, &id, &num)) < 0) return res; if (version) *version = num; break; } default: av_log(matroska->ctx, AV_LOG_INFO, "Unknown data type 0x%x in EBML header", id); /* pass-through */ case EBML_ID_VOID: /* we ignore these two, as they don't tell us anything we * care about */ case EBML_ID_EBMLVERSION: case EBML_ID_DOCTYPEVERSION: res = ebml_read_skip (matroska); break; } } return 0;}/* * Put one packet in an application-supplied AVPacket struct. * Returns 0 on success or -1 on failure. */static intmatroska_deliver_packet (MatroskaDemuxContext *matroska, AVPacket *pkt){ if (matroska->num_packets > 0) { memcpy(pkt, matroska->packets[0], sizeof(AVPacket)); av_free(matroska->packets[0]); if (matroska->num_packets > 1) { memmove(&matroska->packets[0], &matroska->packets[1], (matroska->num_packets - 1) * sizeof(AVPacket *)); matroska->packets = av_realloc(matroska->packets, (matroska->num_packets - 1) * sizeof(AVPacket *)); } else { av_free(matroska->packets); matroska->packets = NULL; } matroska->num_packets--; return 0; } return -1;}/* * Put a packet into our internal queue. Will be delivered to the * user/application during the next get_packet() call. */static voidmatroska_queue_packet (MatroskaDemuxContext *matroska, AVPacket *pkt){ matroska->packets = av_realloc(matroska->packets, (matroska->num_packets + 1) * sizeof(AVPacket *)); matroska->packets[matroska->num_packets] = pkt; matroska->num_packets++;}/* * Autodetecting... */static intmatroska_probe (AVProbeData *p){ uint64_t total = 0; int len_mask = 0x80, size = 1, n = 1; uint8_t probe_data[] = { 'm', 'a', 't', 'r', 'o', 's', 'k', 'a' }; if (p->buf_size < 5) return 0; /* ebml header? */ if ((p->buf[0] << 24 | p->buf[1] << 16 | p->buf[2] << 8 | p->buf[3]) != EBML_ID_HEADER) return 0; /* length of header */ total = p->buf[4]; while (size <= 8 && !(total & len_mask)) { size++; len_mask >>= 1; } if (size > 8) return 0; total &= (len_mask - 1); while (n < size) total = (total << 8) | p->buf[4 + n++]; /* does the probe data contain the whole header? */ if (p->buf_size < 4 + size + total) return 0; /* the header must contain the document type 'matroska'. For now, * we don't parse the whole header but simply check for the * availability of that array of characters inside the header. * Not fully fool-proof, but good enough. */ for (n = 4 + size; n < 4 + size + total - sizeof(probe_data); n++) if (!memcmp (&p->buf[n], probe_data, sizeof(probe_data))) return AVPROBE_SCORE_MAX; return 0;}/* * From here on, it's all XML-style DTD stuff... Needs no comments. */static intmatroska_parse_info (MatroskaDemuxContext *matroska){ int res = 0; uint32_t id; av_log(matroska->ctx, AV_LOG_DEBUG, "Parsing info...\n"); while (res == 0) { if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { res = AVERROR_IO; break; } else if (matroska->level_up) { matroska->level_up--; break; } switch (id) { /* cluster timecode */ case MATROSKA_ID_TIMECODESCALE: { uint64_t num; if ((res = ebml_read_uint(matroska, &id, &num)) < 0) break; matroska->time_scale = num; break; } case MATROSKA_ID_DURATION: { double num; if ((res = ebml_read_float(matroska, &id, &num)) < 0) break; matroska->ctx->duration = num * matroska->time_scale * 1000 / AV_TIME_BASE; break; } case MATROSKA_ID_WRITINGAPP: { char *text; if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) break; matroska->writing_app = text; break; } case MATROSKA_ID_MUXINGAPP: { char *text; if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) break; matroska->muxing_app = text; break; } case MATROSKA_ID_DATEUTC: { int64_t time; if ((res = ebml_read_date(matroska, &id, &time)) < 0) break; matroska->created = time; break; } default: av_log(matroska->ctx, AV_LOG_INFO, "Unknown entry 0x%x in info header\n", id); /* fall-through */ case EBML_ID_VOID: res = ebml_read_skip(matroska); break; } if (matroska->level_up) { matroska->level_up--; break; } } return res;}static intmatroska_add_stream (MatroskaDemuxContext *matroska){ int res = 0; uint32_t id; MatroskaTrack *track; av_log(matroska->ctx, AV_LOG_DEBUG, "parsing track, adding stream..,\n"); /* Allocate a generic track. As soon as we know its type we'll realloc. */ track = av_mallocz(sizeof(MatroskaTrack)); matroska->num_tracks++; /* start with the master */ if ((res = ebml_read_master(matroska, &id)) < 0) return res; /* try reading the trackentry headers */ while (res == 0) { if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { res = AVERROR_IO; break; } else if (matroska->level_up > 0) { matroska->level_up--; break; } switch (id) { /* track number (unique stream ID) */ case MATROSKA_ID_TRACKNUMBER: { uint64_t num; if ((res = ebml_read_uint(matroska, &id, &num)) < 0) break; track->num = num; break; } /* track UID (unique identifier) */ case MATROSKA_ID_TRACKUID: { uint64_t num; if ((res = ebml_read_uint(matroska, &id, &num)) < 0) break; track->uid = num; break; } /* track type (video, audio, combined, subtitle, etc.) */ case MATROSKA_ID_TRACKTYPE: { uint64_t num; if (track->type != 0) { av_log(matroska->ctx, AV_LOG_INFO, "More than one tracktype in an entry - skip\n"); break; } if ((res = ebml_read_uint(matroska, &id, &num)) < 0) break; track->type = num; /* ok, so we're actually going to reallocate this thing */ switch (track->type) { case MATROSKA_TRACK_TYPE_VIDEO: track = (MatroskaTrack *) av_realloc(track, sizeof(MatroskaVideoTrack)); break; case MATROSKA_TRACK_TYPE_AUDIO: track = (MatroskaTrack *) av_realloc(track, sizeof(MatroskaAudioTrack)); ((MatroskaAudioTrack *)track)->channels = 1; ((MatroskaAudioTrack *)track)->samplerate = 8000; break; case MATROSKA_TRACK_TYPE_SUBTITLE: track = (MatroskaTrack *) av_realloc(track, sizeof(MatroskaSubtitleTrack)); break; case MATROSKA_TRACK_TYPE_COMPLEX: case MATROSKA_TRACK_TYPE_LOGO: case MATROSKA_TRACK_TYPE_CONTROL: default: av_log(matroska->ctx, AV_LOG_INFO, "Unknown or unsupported track type 0x%x\n", track->type); track->type = 0; break; } matroska->tracks[matroska->num_tracks - 1] = track; break; } /* tracktype specific stuff for video */ case MATROSKA_ID_TRACKVIDEO: { MatroskaVideoTrack *videotrack; if (track->type != MATROSKA_TRACK_TYPE_VIDEO) { av_log(matroska->ctx, AV_LOG_INFO, "video data in non-video track - ignoring\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -