[FFmpeg-devel] [PATCH] encoder for adobe's flash ScreenVideo2 codec

Vitor Sessak vitor1001
Wed Jul 22 17:16:40 CEST 2009


Joshua Warner wrote:
> On Tue, Jul 21, 2009 at 11:23 PM, Vitor Sessak<vitor1001 at gmail.com> wrote:
>> Joshua Warner wrote:
>>> Hi all,
>>>
>>> I've developed an encoder for Adobe's Flash ScreenVideo2 format, which is
>>> stored in flv files.  My encoder currently only supports a large subset of
>>> the format.  The only player that supports this codec (so far) is Adobe
>>> Flash Player itself, but ScreenVideo2 makes dramatic improvement in file
>>> size over ScreenVideo (currently in ffmpeg as flashsv) - and should be
>>> very
>>> useful for uploading screencasts, etc.  Most options (block size, etc) now
>>> just fall back on defaults because I couldn't find a general algorithm
>>> that
>>> produced consistantly better results than these.  All the code is in place
>>> to be able to change these parameters dynamically, so future improvements
>>> there should be easy.  The patch is attached.
>>>
>>> The codec is listed as flashsv2 in ffmpeg.
>> I'll give a few comments...

[...]

>>
>>> +static int new_key_frame(FlashSV2Context * s)
>>> +{
>>> +    int i;
>>> +    memcpy(s->keybuffer, s->encbuffer, s->frame_size);
>> Can't this memcpy() be avoided by doing FFSWAP(s->keybuffer, s->encbuffer)
>> at some point?
> FFSWAP only does swapping on fixed-size types (it uses = assignment)

I meant FFSWAP(uint8_t *, s->keybuffer, s->encbuffer). The main idea was 
to just switch pointers to buffers instead of doing a time-consuming memcpy.

>>> +    memcpy(s->key_blocks, s->frame_blocks, s->blocks_size);
>>> +    memcpy(s->key_frame, s->current_frame, s->frame_size);
>> same for those
> dito
>>> +static int write_block(Block * b, uint8_t * buf, int buf_size)
>>> +{
>>> +    int buf_pos = 0;
>>> +    unsigned block_size = b->data_size;
>>> +
>>> +    if (b->flags & HAS_DIFF_BLOCKS)
>>> +        block_size += 2;
>>> +    if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT)
>>> +        block_size += 2;
>>> +    if (block_size > 0)
>>> +        block_size += 1;
>>> +    if (buf_size < block_size + 2)
>>> +        return -1;
>>> +
>>> +    buf[buf_pos++] = block_size >> 8;
>>> +    buf[buf_pos++] = block_size;
>> See AV_WL16().
>>
>>> +
>>> +    if (block_size == 0)
>>> +        return buf_pos;
>>> +
>>> +    buf[buf_pos++] = b->flags;
>>> +
>>> +    if (b->flags & HAS_DIFF_BLOCKS) {
>>> +        buf[buf_pos++] = (uint8_t) (b->start);
>>> +        buf[buf_pos++] = (uint8_t) (b->len);
>>> +    }
>>> +
>>> +    if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT) {
>>> +        //This feature of the format is poorly understood, and as of now,
>>> unused.
>>> +        buf[buf_pos++] = (uint8_t) (b->col);
>>> +        buf[buf_pos++] = (uint8_t) (b->row);
>>> +    }
>>> +
>>> +    memcpy(buf + buf_pos, b->data, b->data_size);
>> Is it really necessary to memcpy() data, or there is a way to write directly
>> to the buffer?
> I have to try several different compression settings.  There would be
> a messy string of dependencies to resolve in order to figure out
> exactly where to write the data to in the buffer (and depending on
> what the ZLIB_PRIME_COMPRESS_CURRENT flag means in the format (that is
> one feature that my encoder doesn't use yet), resolving these
> dependencies at the time of doing the compression might be
> impossible).  No matter what, I have to write to a temporary buffer to
> try these settings anyway.
>>> +
>>> +static int encode_zlib(Block * b, uint8_t * buf, int *buf_size, int comp)
>>> +{
>>> +    int res =
>>> +        compress2(buf, buf_size, b->sl_begin, b->sl_end - b->sl_begin,
>>> +                  comp);
>>> +    return res == Z_OK ? 0 : -1;
>>> +}
>> I think it would be cleaner to use compress2() directly all over the code,
>> for ex. instead of
> I did it this way for two reasons: 1, so that it fits with the error
> passing protocol shared by the rest of the code, and 2, because it
> nicely mirrors encode_zlibprime.  I am an object-oriented programmer
> at heart, and this is (weak) example of encapsulation - only the
> "encoding" code has to know about the details of the zlib interface.
>>> +        res = encode_zlib(b, b->data, &b->data_size, comp);
>>> +        if (res != 0)
>>> +            return res;
>> just
>>
>> if (compress2(b->data, &b->data_size, b->sl_begin,
>>              b->sl_end - b->sl_begin, comp) != Z_OK)
>>    return -1;
>>
>>
>>> +static inline unsigned pixel_bgr(uint8_t * src)
>>> +{
>>> +    return (src[2]) | (src[1] << 8) | (src[2] << 16);
>>> +}
>>
>> Hm, src[0] is unused?
> You are absolutely right - that code is wrong.  I probably didn't
> notice it because the only place it uses that color is in deciding
> whether to use 7-bit paletted color or 15-bit hybrid color.

Note also that this function is useless if you get input as 
PIX_FMT_RGB32 (which is already in native endianness).

-Vitor



More information about the ffmpeg-devel mailing list