[FFmpeg-devel] ARMovie/RPL demuxer

Michael Niedermayer michaelni
Mon Mar 24 00:02:42 CET 2008


On Sun, Mar 23, 2008 at 12:31:25AM -0700, Eli Friedman wrote:
> Per subject, a ARMovie/RPL demuxer; format documented at
> http://wiki.multimedia.cx/index.php?title=ARMovie, patch adapted from
> http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2007-November/037984.html.
> 
> This implementation can play the audio for all the samples at
> http://samples.mplayerhq.hu/game-formats/rpl/. The video for all those
> samples depends on the various Escape video codecs
> (http://wiki.multimedia.cx/index.php?title=Escape_122,
> http://wiki.multimedia.cx/index.php?title=Escape_124,
> http://wiki.multimedia.cx/index.php?title=Escape_130 /
> http://pirsoft-dsl-dropzone.de/dec130-spec.txt).
> 
> It would be nice if I had more samples to test with, but I'm having
> trouble finding files in this format.  Help here would be appreciated.
> 
> I think I've addressed all the comments from the original review.  The
> part I'm least sure about in this patch is the pts calculations; I
> think what I'm doing is sane, but I'm not entirely sure how pts is
> supposed to work.
[...]
> +// 256 is arbitrary, but should be big enough for any reasonable file.
> +#define RPL_LINE_LENGTH 256

not doxygen compatible comment


[...]
> +typedef struct RPLFrame {
> +    uint32_t offset;
> +    uint32_t video_size;
> +    uint32_t audio_size;
> +} RPLFrame;

instead of your own index system, using 
AStream.index_entries / av_add_index_entry() seems to make more sense.


[...]
> +static int read_line(ByteIOContext * pb, char* line) {
> +    int i;
> +    int b;
> +    for (i = 0; i < RPL_LINE_LENGTH; i++) {
> +        b = get_byte(pb);
> +        if (b == 0)
> +            break;
> +        if (b == '\n') {
> +            line[i] = '\0';
> +            return 0;
> +        }
> +        line[i] = b;
> +    }
> +    return 1;
> +}

add a comment that says that this does not gurantee line to be zero
terminated


> +
> +static int read_int(char* line, uint32_t* number) {
> +  unsigned long result;

inconsistent indention


> +  char* endptr;

> +  errno = 0;
> +  result = strtoul(line, &endptr, 10);
> +  if (endptr == line || errno || result > 0xFFFFFFFFU)
> +    return 1;

I do not like this code at all, the errno access is ugly.

Also error returns are consistently negative numbers in libav*
And i prefer to use return to return the value where possible.


> +  *number = result;
> +  return 0;
> +}
> +

> +static int read_float(char* line, float* number) {
> +  float result;
> +  char* endptr;
> +  errno = 0;
> +  result = strtod(line, &endptr);
> +  if (endptr == line || !isfinite(result))
> +    return 1;
> +  *number = result;
> +  return 0;
> +}

floats are not accurate things, this makes regression tests hard.
The string should be parsed into a AVRational with no intermediate
float/double.


> +
> +static int read_index_entry(char* line, uint32_t* offset, 
> +                            uint32_t* video_size, uint32_t* audio_size) {
> +  unsigned long result;
> +  char* endptr;
> +
> +  errno = 0;
> +  result = strtoul(line, &endptr, 10);
> +  if (endptr == line || errno || result > 0xFFFFFFFFU)
> +    return 1;
> +  *offset = result;
> +  line = endptr;
> +
> +  while (isspace(*line))
> +    line++;
> +  if (*line != ',')
> +    return 1;
> +  line++;
> +
> +  errno = 0;
> +  result = strtoul(line, &endptr, 10);
> +  if (endptr == line || errno || result > 0xFFFFFFFFU)
> +    return 1;
> +  *video_size = result;
> +  line = endptr;

code duplication


[...]
> +    // Movie name
> +    if (read_line(pb, line)) return AVERROR(EIO);
> +
> +    // Date/copyright
> +    if (read_line(pb, line)) return AVERROR(EIO);
> +
> +    // Author and other
> +    if (read_line(pb, line)) return AVERROR(EIO);

There are places for such metadata in AVFormatContext, this should be read
into that.


> +
> +    // Video format
> +    if (read_line(pb, line)) return AVERROR(EIO);
> +    if (read_int(line, &rpl->video_format)) return AVERROR(EIO);
> +
> +    // Video width
> +    if (read_line(pb, line)) return AVERROR(EIO);
> +    if (read_int(line, &rpl->video_width)) return AVERROR(EIO);
> +
> +    // Video height
> +    if (read_line(pb, line)) return AVERROR(EIO);
> +    if (read_int(line, &rpl->video_height)) return AVERROR(EIO);

These things should be directly read into AVCodecContext with no
intermediate if possible.


> +
> +    // Video bits per pixel
> +    if (read_line(pb, line)) return AVERROR(EIO);

Should be stored in bits_per_sample


[...]
> +    if (rpl->number_of_chunks >= SIZE_MAX / sizeof(RPLFrame))
> +        return AVERROR(ENOMEM);
> +    rpl->index = av_malloc(rpl->number_of_chunks * sizeof(RPLFrame));

av_malloc() takes a unsigned int so this check is not correct.


[...]
> +        default:
> +            av_log(NULL, AV_LOG_WARNING,

all new av_log() should have a context


> +                   "RPL video format %i not supported yet!\n",
> +                   rpl->video_format);
> +            vst->codec->codec_id = CODEC_ID_NONE;
> +    }
> +    vst->codec->width = rpl->video_width;
> +    vst->codec->height = rpl->video_height;
> +    r = av_d2q(rpl->fps, DEFAULT_FRAME_RATE_BASE);
> +    av_set_pts_info(vst, 32, r.num, r.den);
> +
> +    if (rpl->audio_format) {
> +        ast = av_new_stream(s, 0);
> +        if (!ast)
> +            return AVERROR(ENOMEM);
> +        ast->codec->codec_type = CODEC_TYPE_AUDIO;
> +        ast->codec->channels = rpl->audio_channels;
> +        ast->codec->sample_rate = rpl->audio_rate;
> +        ast->codec->bits_per_sample = rpl->audio_bps;
> +        ast->codec->bit_rate = rpl->audio_rate * rpl->audio_bps * rpl->audio_channels;
> +
> +        ast->codec->codec_id = CODEC_ID_NONE;
> +        switch (rpl->audio_format) {

codec_tag= rpl->audio_format
same for video


[...]
> +        ret = av_get_packet(pb, pkt, fr->video_size);
> +        if (ret != fr->video_size)
> +            return AVERROR(EIO);

memleak


> +
> +        // There should always be frames_per_chunk frames in a chunk.
> +        // (This should be checked once video decoding is implemented.)
> +        pkt->duration = rpl->frames_per_chunk;

1 AVPacket == 1 frame. Either demuxer or parser has to split them if there
are more.


> +        pkt->pts = rpl->chunk_number * rpl->frames_per_chunk;
> +        pkt->stream_index = 0;
> +    } else {
> +        url_fseek(pb, fr->offset + fr->video_size, SEEK_SET);
> +        ret = av_get_packet(pb, pkt, fr->audio_size);
> +        if (ret != fr->audio_size)
> +            return AVERROR(EIO);
> +
> +        // All the audio codecs supported in this container
> +        // (at least so far) are constant-bitrate.
> +        // The container apparently doesn't require a constant number
> +        // of samples per packet.
> +        pkt->duration = ret * 8;
> +        pkt->pts = rpl->audio_timestamp;
> +        rpl->audio_timestamp += pkt->duration;
> +        pkt->stream_index = 1;
> +    }
> +

> +    pkt->size = ret;

unneeded

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

I count him braver who overcomes his desires than him who conquers his
enemies for the hardest victory is over self. -- 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/20080324/9218e8c4/attachment.pgp>



More information about the ffmpeg-devel mailing list