📄 matroskadec.c
字号:
/*
* Put one packet in an application-supplied AVPacket struct.
* Returns 0 on success or -1 on failure.
*/
static int
matroska_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_freep(&matroska->packets);
}
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 void
matroska_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 int
matroska_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' };
/* ebml header? */
if (AV_RB32(p->buf) != 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 int
matroska_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(EIO);
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_TITLE: {
char *text;
if ((res = ebml_read_utf8(matroska, &id, &text)) < 0)
break;
strncpy(matroska->ctx->title, text,
sizeof(matroska->ctx->title)-1);
av_free(text);
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 int
matroska_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(MAX_TRACK_SIZE);
matroska->num_tracks++;
strcpy(track->language, "eng");
/* 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(EIO);
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 ((res = ebml_read_uint(matroska, &id, &num)) < 0)
break;
if (track->type && track->type != num) {
av_log(matroska->ctx, AV_LOG_INFO,
"More than one tracktype in an entry - skip\n");
break;
}
track->type = num;
switch (track->type) {
case MATROSKA_TRACK_TYPE_VIDEO:
case MATROSKA_TRACK_TYPE_AUDIO:
case MATROSKA_TRACK_TYPE_SUBTITLE:
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)
track->type = MATROSKA_TRACK_TYPE_VIDEO;
if (track->type != MATROSKA_TRACK_TYPE_VIDEO) {
av_log(matroska->ctx, AV_LOG_INFO,
"video data in non-video track - ignoring\n");
res = AVERROR_INVALIDDATA;
break;
} else if ((res = ebml_read_master(matroska, &id)) < 0)
break;
videotrack = (MatroskaVideoTrack *)track;
while (res == 0) {
if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
res = AVERROR(EIO);
break;
} else if (matroska->level_up > 0) {
matroska->level_up--;
break;
}
switch (id) {
/* fixme, this should be one-up, but I get it here */
case MATROSKA_ID_TRACKDEFAULTDURATION: {
uint64_t num;
if ((res = ebml_read_uint (matroska, &id,
&num)) < 0)
break;
track->default_duration = num;
break;
}
/* video framerate */
case MATROSKA_ID_VIDEOFRAMERATE: {
double num;
if ((res = ebml_read_float(matroska, &id,
&num)) < 0)
break;
if (!track->default_duration)
track->default_duration = 1000000000/num;
break;
}
/* width of the size to display the video at */
case MATROSKA_ID_VIDEODISPLAYWIDTH: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id,
&num)) < 0)
break;
videotrack->display_width = num;
break;
}
/* height of the size to display the video at */
case MATROSKA_ID_VIDEODISPLAYHEIGHT: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id,
&num)) < 0)
break;
videotrack->display_height = num;
break;
}
/* width of the video in the file */
case MATROSKA_ID_VIDEOPIXELWIDTH: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id,
&num)) < 0)
break;
videotrack->pixel_width = num;
break;
}
/* height of the video in the file */
case MATROSKA_ID_VIDEOPIXELHEIGHT: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id,
&num)) < 0)
break;
videotrack->pixel_height = num;
break;
}
/* whether the video is interlaced */
case MATROSKA_ID_VIDEOFLAGINTERLACED: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id,
&num)) < 0)
break;
if (num)
track->flags |=
MATROSKA_VIDEOTRACK_INTERLACED;
else
track->flags &=
~MATROSKA_VIDEOTRACK_INTERLACED;
break;
}
/* stereo mode (whether the video has two streams,
* where one is for the left eye and the other for
* the right eye, which creates a 3D-like
* effect) */
case MATROSKA_ID_VIDEOSTEREOMODE: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id,
&num)) < 0)
break;
if (num != MATROSKA_EYE_MODE_MONO &&
num != MATROSKA_EYE_MODE_LEFT &&
num != MATROSKA_EYE_MODE_RIGHT &&
num != MATROSKA_EYE_MODE_BOTH) {
av_log(matroska->ctx, AV_LOG_INFO,
"Ignoring unknown eye mode 0x%x\n",
(uint32_t) num);
break;
}
videotrack->eye_mode = num;
break;
}
/* aspect ratio behaviour */
case MATROSKA_ID_VIDEOASPECTRATIO: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id,
&num)) < 0)
break;
if (num != MATROSKA_ASPECT_RATIO_MODE_FREE &&
num != MATROSKA_ASPECT_RATIO_MODE_KEEP &&
num != MATROSKA_ASPECT_RATIO_MODE_FIXED) {
av_log(matroska->ctx, AV_LOG_INFO,
"Ignoring unknown aspect ratio 0x%x\n",
(uint32_t) num);
break;
}
videotrack->ar_mode = num;
break;
}
/* colourspace (only matters for raw video)
* fourcc */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -