summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvan <[email protected]>2008-10-26 03:33:29 +0000
committervan <[email protected]>2008-10-26 03:33:29 +0000
commiteac5404f25a729ffef6aeb92fa379db76badb1a4 (patch)
tree9e2babb85f194136a8f4080cafb7b8a8d844d46c
parent54f291c822357595718264fe167cf63c25e5fbb8 (diff)
If an input uses a different color space than YUV420 (for example DV video uses YUV411) convert it to YUV420. Also, scale down inputs that have an odd width or height since h.264 requires that the width and height be even.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1867 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--libhb/decavcodec.c58
1 files changed, 49 insertions, 9 deletions
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index 63ed879ac..e215aef9f 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -63,6 +63,7 @@
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
+#include "libswscale/swscale.h"
static int decavcodecInit( hb_work_object_t *, hb_job_t * );
static int decavcodecWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
@@ -108,6 +109,7 @@ struct hb_work_private_s
hb_buffer_t* delayq[HEAP_SIZE];
pts_heap_t pts_heap;
void* buffer;
+ struct SwsContext *sws_context; // if we have to rescale or convert color space
};
static int64_t heap_pop( pts_heap_t *heap )
@@ -214,6 +216,10 @@ static void decavcodecClose( hb_work_object_t * w )
pv->context->codec->name, pv->nframes, pv->decode_errors,
pv->ndrops );
}
+ if ( pv->sws_context )
+ {
+ sws_freeContext( pv->sws_context );
+ }
if ( pv->parser )
{
av_parser_close(pv->parser);
@@ -401,18 +407,52 @@ static uint8_t *copy_plane( uint8_t *dst, uint8_t* src, int dstride, int sstride
return dst;
}
-/* Note: assumes frame format is PIX_FMT_YUV420P */
-static hb_buffer_t *copy_frame( AVCodecContext *context, AVFrame *frame )
+// copy one video frame into an HB buf. If the frame isn't in our color space
+// or at least one of its dimensions is odd, use sws_scale to convert/rescale it.
+// Otherwise just copy the bits.
+static hb_buffer_t *copy_frame( hb_work_private_t *pv, AVFrame *frame )
{
- int w = context->width, h = context->height;
+ AVCodecContext *context = pv->context;
+ int w, h;
+ if ( ! pv->job )
+ {
+ // if the dimensions are odd, drop the lsb since h264 requires that
+ // both width and height be even.
+ w = ( context->width >> 1 ) << 1;
+ h = ( context->height >> 1 ) << 1;
+ }
+ else
+ {
+ w = pv->job->title->width;
+ h = pv->job->title->height;
+ }
hb_buffer_t *buf = hb_buffer_init( w * h * 3 / 2 );
uint8_t *dst = buf->data;
- dst = copy_plane( dst, frame->data[0], w, frame->linesize[0], h );
- w >>= 1; h >>= 1;
- dst = copy_plane( dst, frame->data[1], w, frame->linesize[1], h );
- dst = copy_plane( dst, frame->data[2], w, frame->linesize[2], h );
+ if ( context->pix_fmt != PIX_FMT_YUV420P || w != context->width ||
+ h != context->height )
+ {
+ // have to convert to our internal color space and/or rescale
+ AVPicture dstpic;
+ avpicture_fill( &dstpic, dst, PIX_FMT_YUV420P, w, h );
+ if ( ! pv->sws_context )
+ {
+ pv->sws_context = sws_getContext( context->width, context->height, context->pix_fmt,
+ w, h, PIX_FMT_YUV420P,
+ SWS_LANCZOS|SWS_ACCURATE_RND,
+ NULL, NULL, NULL );
+ }
+ sws_scale( pv->sws_context, frame->data, frame->linesize, 0, h,
+ dstpic.data, dstpic.linesize );
+ }
+ else
+ {
+ dst = copy_plane( dst, frame->data[0], w, frame->linesize[0], h );
+ w >>= 1; h >>= 1;
+ dst = copy_plane( dst, frame->data[1], w, frame->linesize[1], h );
+ dst = copy_plane( dst, frame->data[2], w, frame->linesize[2], h );
+ }
return buf;
}
@@ -503,7 +543,7 @@ static int decodeFrame( hb_work_private_t *pv, uint8_t *data, int size )
// by Microsoft we don't worry about timestamp reordering
if ( ! pv->job || ! pv->brokenByMicrosoft )
{
- buf = copy_frame( pv->context, &frame );
+ buf = copy_frame( pv, &frame );
buf->start = pts;
hb_list_add( pv->list, buf );
++pv->nframes;
@@ -552,7 +592,7 @@ static int decodeFrame( hb_work_private_t *pv, uint8_t *data, int size )
}
// add the new frame to the delayq & push its timestamp on the heap
- pv->delayq[slot] = copy_frame( pv->context, &frame );
+ pv->delayq[slot] = copy_frame( pv, &frame );
heap_push( &pv->pts_heap, pts );
++pv->nframes;