[FFmpeg-devel] [PATCH] Matroska Muxer

Michael Niedermayer michaelni
Tue Aug 14 21:13:49 CEST 2007


Hi

On Mon, Aug 13, 2007 at 08:38:25PM -0400, David Conrad wrote:
> Hi,
>
> I feel that my GSoC is ready for SVN. It does have a couple of known 
> limitations:
>
[...]
> 2. Stream copy from raw flac doesn't work since the demuxer passes the 
> extradata in the first packet. I think it would be preferable to change the 
> demuxer?

implement AVCodecParser.split() for flac


[...]
> As for applying this, I plan on using git-svn to push the history of 
> matroskaenc.c, then apply the rest of the patch to enable it in one go. 
> Does that sound okay?

yes commiting the whole history is preferred


>
> Comments and more testing welcome.

[...]

> +// 2 bytes * 3 for EBML IDs, 3 1-byte EBML lengths, 8 bytes for 64 bit offset, 4 bytes for target EBML ID
> +#define MAX_SEEKENTRY_SIZE 21

not doxygen compatible comment


> +
> +// per-cuepoint-track - 3 1-byte EBML IDs, 3 1-byte EBML sizes, 2 8-byte uint max
> +#define MAX_CUETRACKPOS_SIZE 22
> +
> +// per-cuepoint - 2 1-byte EBML IDs, 2 1-byte EBML sizes, 8-byte uint max
> +#define MAX_CUEPOINT_SIZE(num_tracks) 12 + MAX_CUETRACKPOS_SIZE*num_tracks
> +
> +
> +static int ebml_id_size(unsigned int id)
> +{
> +    return (av_log2(id+1)-1)/7+1;
> +}
> +
> +static void put_ebml_id(ByteIOContext *pb, unsigned int id)
> +{
> +    int i = ebml_id_size(id);
> +    while (i--)
> +        put_byte(pb, id >> (i*8));
> +}
> +
> +/**
> + * Write an EBML size meaning "unknown size"
> + *
> + * @param bytes The number of bytes the size should occupy. Maximum of 8.
> + */
> +static void put_ebml_size_unknown(ByteIOContext *pb, int bytes)
> +{
> +    uint64_t value = 0;
> +    int i;
> +
> +    bytes = FFMIN(bytes, 8);

what is this good for? >8 is not supported yes but it wont work any better
with such checks if its over 8


> +    for (i = 0; i < bytes*7 + 1; i++)
> +        value |= 1ULL << i;
> +    for (i = bytes-1; i >= 0; i--)
> +        put_byte(pb, value >> i*8);

put_byte(pb, 0x1FF>>bytes);
while(--bytes)
    put_byte(pb, 0xFF);


> +}
> +
> +/**
> + * Calculate how many bytes are needed to represent a given size in EBML
> + */
> +static int ebml_size_bytes(uint64_t size)
> +{
> +    int bytes = 1;
> +    while ((size+1) >> bytes*7) bytes++;
> +    return bytes;
> +}

isnt ebml_size_bytes and ebml_id_size the same if the IDs would be stored
properly?
i mean currently the #define *_ID_* is in encoded form while size of course
cannot be, so if we would change the #defines to be in normal form then i
think this could allow some simplifications, though i might be wrong ...


> +
> +/**
> + * Write a size in EBML variable length format.
> + *
> + * @param bytes The number of bytes that need to be used to write the size.
> + *              If zero, any number of bytes can be used.
> + */
> +static void put_ebml_size(ByteIOContext *pb, uint64_t size, int bytes)
> +{
> +    int i, needed_bytes = ebml_size_bytes(size);
> +

> +    // sizes larger than this are currently undefined in EBML
> +    // so write "unknown" size
> +    if (size >= (1ULL<<56)-1) {
> +        put_ebml_size_unknown(pb, 1);
> +        return;
> +    }
> +
> +    if (bytes == 0)
> +        // don't care how many bytes are used, so use the min
> +        bytes = needed_bytes;
> +    else if (needed_bytes > bytes) {
> +        // the bytes needed to write the given size would exceed the bytes
> +        // that we need to use, so write unknown size. This shouldn't happen.

if it shoulnt happen then it should be an assert()


[...]
> + * @param size The number of bytes to reserve, which must be at least 2.
> + */
> +static void put_ebml_void(ByteIOContext *pb, uint64_t size)
> +{
> +    offset_t currentpos = url_ftell(pb);
> +
> +    if (size < 2)
> +        return;

that should be an assert() and of course size must never be <2
all checks which cant be true unless theres a bug somewhere in our code
should be assert()


[...]
> +static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid, uint64_t filepos)
> +{
> +    mkv_seekhead_entry *entries = seekhead->entries;
> +    int new_entry = seekhead->num_entries;
> +
> +    // don't store more elements than we reserved space for
> +    if (seekhead->max_entries > 0 && seekhead->max_entries <= seekhead->num_entries)
> +        return -1;
> +
> +    entries = av_realloc(entries, (seekhead->num_entries + 1) * sizeof(mkv_seekhead_entry));
> +    if (entries == NULL)
> +        return -1;

this should be AVERROR(ENOMEM)
also not every call to this function checks the return value


> +
> +    entries[new_entry].elementid = elementid;
> +    entries[new_entry].segmentpos = filepos - seekhead->segment_offset;
> +
> +    seekhead->entries = entries;
> +    seekhead->num_entries++;

the code mixes seekhead->num_entries and the local copy new_entry

i would write
entries[seekhead->num_entries  ].elementid  = elementid;
entries[seekhead->num_entries++].segmentpos = filepos - seekhead->segment_offset;

but using new_entry everywhere is fine too, just the mix of both is
a little confusing


[...]

> +                case CODEC_TYPE_SUBTITLE:
> +                    put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_SUBTITLE);
> +                    break;
> +            default:
> +                av_log(s, AV_LOG_ERROR, "Only audio and video are supported for Matroska.");
> +                break;

indention, and contradiction


[...]
> +    mkv->segment = start_ebml_master(pb, MATROSKA_ID_SEGMENT, 0);
> +    mkv->segment_offset = url_ftell(pb);
> +
> +    // we write 2 seek heads - one at the end of the file to point to each cluster, and
> +    // one at the beginning to point to all other level one elements (including the seek
> +    // head at the end of the file), which isn't more than 10 elements if we only write one
> +    // of each other currently defined level 1 element
> +    mkv->main_seekhead    = mkv_start_seekhead(pb, mkv->segment_offset, 10);

i assume matroska needs seekable destination ...


[...]
> +    mkv->duration = pkt->pts + pkt->duration;

FFMAX(mkv->duration, pkt->pts + pkt->duration);


[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

No great genius has ever existed without some touch of madness. -- Aristotle
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20070814/d7d0a337/attachment.pgp>



More information about the ffmpeg-devel mailing list