great code, worked perfectly on my app. :)

just one thing, I'm moving all initializers globally as I don't need to
change quality, but I need it to be really fast.

anyway, thanks alot :)

Bogdan Coanda

On Thu, Apr 2, 2009 at 7:29 PM, Clive Taylor <[email protected]> wrote:

> Stas,
>
> An update (quite a long one I'm afraid). I changed my code so that all
> of the JPEG writing stuff goes into its own function as below (once
> again, the e-mail system has ruined all of my beautiful code
> formatting):
>
> //
> //      Write JPEG
> //
> //      Converts and writes the video frame in pFrame to a JPEG file
> //
> //      Parameters:
> //              pCodexCtx       Pointer to the video stream codec
> context
> //              pFrame  Pointer to Frame exracted from the video stream
> //              FrameNo FrameNumber
> //              Quality Image quality as %
> //
> //      Returns:
> //              Size of buffer written or 0 on error
> //
> int
> WriteJPEG ( AVCodecContext *pCodecCtx, AVFrame *pFrame, int FrameNo, int
> Quality )
> {
>        AVCodecContext  *pOCodecCtx;
>        AVCodec           *pOCodec;
>        BYTE                    *Buffer;
>        int                     BufSiz;
>        int                     BufSizActual;
>        int                     ImgFmt = PIX_FMT_YUVJ420P;
>        FILE                    *JPEGFile;
>        char                    JPEGFName[256];
>
>        BufSiz = avpicture_get_size ( ImgFmt,
>                                    pCodecCtx->width,
>                                    pCodecCtx->height );
>        //
>        //      Allocate local RGB frame buffer
>        //
>        Buffer = (BYTE *)malloc ( BufSiz );
>        if ( Buffer == NULL )
>                return ( 0 );
>        memset ( Buffer, 0, BufSiz );
>         //
>        //      Allocate the output codec context
>        //
>        pOCodecCtx = avcodec_alloc_context ( );
>        if ( !pOCodecCtx ) {
>                 free ( Buffer );
>                return ( 0 );
>                 }
>        //
>        //      Initialise format parameters
>        //
>        pOCodecCtx->bit_rate      = pCodecCtx->bit_rate;
>        pOCodecCtx->width         = pCodecCtx->width;
>        pOCodecCtx->height        = pCodecCtx->height;
>        pOCodecCtx->pix_fmt       = ImgFmt;
>        pOCodecCtx->codec_id      = CODEC_ID_MJPEG;
>        pOCodecCtx->codec_type    = CODEC_TYPE_VIDEO;
>        pOCodecCtx->time_base.num = pCodecCtx->time_base.num;
>        pOCodecCtx->time_base.den = pCodecCtx->time_base.den;
>        //
>        //      Allocate the JPEG encoder
>        //
>        pOCodec = avcodec_find_encoder ( pOCodecCtx->codec_id );
>        if ( !pOCodec ) {
>                 free ( Buffer );
>                return ( 0 );
>                 }
>        //
>        //      Open the JPEG encoder
>        //
>        if ( avcodec_open ( pOCodecCtx, pOCodec ) < 0 ) {
>                 free ( Buffer );
>                return ( 0 );
>                }
>        //
>        //      Initialise the "VBR" settings
>        //
>        pOCodecCtx->qmin           = pOCodecCtx->qmax = Quality;
> pOCodecCtx->mb_lmin        = pOCodecCtx->lmin =
>                                            pOCodecCtx->qmin *
> FF_QP2LAMBDA;
>        pOCodecCtx->mb_lmax        = pOCodecCtx->lmax =
>                                            pOCodecCtx->qmax *
> FF_QP2LAMBDA;
>        pOCodecCtx->flags          = CODEC_FLAG_QSCALE;
>         pOCodecCtx->global_quality = pOCodecCtx->qmin * FF_QP2LAMBDA;
>         //
>        //      Set the timestamp and quality parameters
>        //
>        pFrame->pts     = 1;
>        pFrame->quality = pOCodecCtx->global_quality;
>         BufSizActual = avcodec_encode_video ( pOCodecCtx,
>                                            Buffer,
>                                            BufSiz,
>                                            pFrame );
>        //
>        //      Write JPEG to file
>        //
>         sprintf ( JPEGFName, "f%06dq%02d.jpg", FrameNo, Quality );
>         JPEGFile = fopen ( JPEGFName, "wb" );
>        fwrite ( Buffer, 1, BufSizActual, JPEGFile );
>        fclose ( JPEGFile );
>         //
>        //      Clean up and exit
>        //
>        avcodec_close ( pOCodecCtx );
>        free ( Buffer );
>        return ( BufSizActual );
> }
>
> I then tried invoking it with different values for the Quality
> parameter, in three different ways:
>
> 1)
> ==
> for ( QNo = 1; QNo < 100; QNo++ ) {
>        //
>        //      Encode the frame as a JPEG image
>        //
>         Quality = (100 - QNo) * FF_LAMBDA_MAX / 100;
>        WriteJPEG ( pCodecCtx, pFrame, i, Quality );
>        }
>
> 2)
> ==
> for ( QNo = 1; QNo < 32; QNo++ ) {
>         //
>        //      Encode the frame as a JPEG image
>        //
>         WriteJPEG ( pCodecCtx, pFrame, i, QNo );
>        }
>
> 3)
> ==
> for ( QNo = 1; QNo < 150; QNo++ ) {
>         //
>        //      Encode the frame as a JPEG image
>        //
>         WriteJPEG ( pCodecCtx, pFrame, i, QNo );
>        }
>
> 1) produced all 100 files at 11556 bytes and no differences between them
> (using fc to compare the files).
>
> 2) produced files 31 files (f008000q01.jpg - f008000q31.jpg), but with
> sizes in the range 113,112 bytes (QNo = 1) to 17,381 bytes (QNo = 31)
> and very different visual results - the compression artefacts were
> getting much more visible as the size decreased QNo increased (ah ha,
> we're getting somewhere)
>
> 3) In an attempt to see what the maximum value for QNo would be to
> continue to affect the output, I first tried using 1 - FF_LAMBDA_MAX
> (32767), but got bored after about 10,000 files were produced. So I cut
> the limit down to 150 and tried again. I found decreasing output file
> sizes in the range 1-128, after which the file did not change in size.
> As before with QNo = 1 I got a file of 113,112 bytes and with 128 a file
> of 11556 bytes (above 128, all files were 11556 - even when I allowed it
> to output 10,000 files with changing QNo).
>
> My conclusion is that setting qmin and qmax to a value between 1 and 128
> gives us the variable quality, that the FF_LAMBDA_MAX value is a red
> herring, that to scale the quality so it's expressed as a percentage
> we'd use (100 - Qp) * 128 / 100.
>
> It is necessary to close the codec when the required quality changes (or
> as VOid pointed out when the height and/or width changes, too), and to
> encode more than one frame at the same quality it is necessary to change
> the pts value - whether it's just a simple increment I'm not sure.
> That's how I changed it in previous experiments, and it seems reasonable
> as the encoder would expect sequentially numbered frames.
>
> So I will now finish off my frame extraction program, allowing the
> customer to specify any number of frames from any number of video files
> at any given quality and any given width/height. Luckily I've written it
> as a scripting language for him, so all I need to do is collect all of
> the same input file, quality and dimensions together and process those
> in one hit, close the codec and so on.
>
> Clive
>
>
> -----Original Message-----
> From: [email protected]
> [mailto:[email protected]] On Behalf Of Stas Oskin
> Sent: 02 April 2009 16:01
> To: Libav* user questions and discussions
> Subject: Re: [libav-user] Writing single frames to JPEG
>
> 2009/4/2 Clive Taylor <[email protected]>
>
> > Oh yes. I also tried it with values in the range 1 & 31 and no
> > difference.
> >
> > Clive
> >
>
> Ahh, so  Lambda really needs to be used it seems?
> _______________________________________________
> libav-user mailing list
> [email protected]
> https://lists.mplayerhq.hu/mailman/listinfo/libav-user
>
>
> _______________________________________________
> libav-user mailing list
> [email protected]
> https://lists.mplayerhq.hu/mailman/listinfo/libav-user
>



-- 
Bogdan COANDA

AIESEC Iasi
AIESEC in Romania

Mobile: +40-724 013 068
E-mail: [email protected]
Website: www.aieseciasi.ro

_____________________________________________________________________________
AIESEC - The international platform for young people to discover and develop
their potential
_______________________________________________
libav-user mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/libav-user

Reply via email to