summaryrefslogtreecommitdiffstats
path: root/libhb/decmpeg2.c
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2012-03-27 20:11:26 +0000
committerjstebbins <[email protected]>2012-03-27 20:11:26 +0000
commit45b8f81a2e184e2b7deaf47afc49483766191a27 (patch)
tree30ed0892995cb4ad3255909f69269c453000800a /libhb/decmpeg2.c
parent7eb7737023be00fa0dc9be75a4984b80c0e5ce57 (diff)
Rework filter pipeline
This patch enhances the filter objects. The 2 key improvements are: 1. A filter can change the image dimensions as frames pass through it. 2. A filter can output more than one frame. In addition, I have: Moved cropping & scalling into a filter object Added 90 degree rotation to the rotate filter Moved subtitle burn-in rendering to a filter object. Moved VFR/CFR handling into a framerate shaping filter object. Removed render.c since all it's responsibilities got moved to filters. Improves VOBSUB and SSA subtitle handling. Allows subtitle animations. SSA karaoke support. My apologies in advance if anything breaks ;) git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4546 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/decmpeg2.c')
-rw-r--r--libhb/decmpeg2.c149
1 files changed, 87 insertions, 62 deletions
diff --git a/libhb/decmpeg2.c b/libhb/decmpeg2.c
index f37ee9022..7379964cf 100644
--- a/libhb/decmpeg2.c
+++ b/libhb/decmpeg2.c
@@ -57,6 +57,11 @@ typedef struct hb_libmpeg2_s
int64_t start; // start time of this frame
hb_buffer_t * cc_buf; // captions for this frame
} tags[NTAGS];
+
+ struct SwsContext *sws_context; // if we have to rescale or convert color space
+ int sws_width;
+ int sws_height;
+ int sws_pix_fmt;
} hb_libmpeg2_t;
/**********************************************************************
@@ -95,7 +100,7 @@ static void cc_send_to_decoder( hb_libmpeg2_t *m, hb_buffer_t *cc_buf )
{
// make a copy of the buf then forward it to the decoder
hb_buffer_t *cpy = hb_buffer_init( cc_buf->size );
- hb_buffer_copy_settings( cpy, cc_buf );
+ cpy->s = cc_buf->s;
memcpy( cpy->data, cc_buf->data, cc_buf->size );
subtitle = hb_list_item( m->list_subtitle, i++ );
@@ -251,21 +256,37 @@ static void next_tag( hb_libmpeg2_t *m, hb_buffer_t *buf_es )
if ( m->tags[m->cur_tag].start < 0 ||
( m->got_iframe && m->tags[m->cur_tag].start >= m->first_pts ) )
hb_log("mpeg2 tag botch: pts %"PRId64", tag pts %"PRId64" buf 0x%p",
- buf_es->start, m->tags[m->cur_tag].start, m->tags[m->cur_tag].cc_buf);
+ buf_es->s.start, m->tags[m->cur_tag].start, m->tags[m->cur_tag].cc_buf);
if ( m->tags[m->cur_tag].cc_buf )
hb_buffer_close( &m->tags[m->cur_tag].cc_buf );
}
- m->tags[m->cur_tag].start = buf_es->start;
+ m->tags[m->cur_tag].start = buf_es->s.start;
mpeg2_tag_picture( m->libmpeg2, m->cur_tag, 0 );
}
-static hb_buffer_t *hb_copy_frame( hb_job_t *job, int width, int height,
- int *crop, enum PixelFormat pixfmt,
- uint8_t* y, uint8_t *u, uint8_t *v )
+static hb_buffer_t *hb_copy_frame( hb_libmpeg2_t *m )
{
+ hb_job_t * job = m->job;
+ int width = m->info->sequence->width;
+ int height = m->info->sequence->height;
+ enum PixelFormat pixfmt = m->pixfmt;
+ uint8_t *y = m->info->display_fbuf->buf[0];
+ uint8_t *u = m->info->display_fbuf->buf[1];
+ uint8_t *v = m->info->display_fbuf->buf[2];
+ int crop[4] = {0};
+
int dst_w, dst_h;
int src_w, src_h;
+ if ( m->info->sequence->picture_width < m->info->sequence->width )
+ {
+ crop[3] = m->info->sequence->width - m->info->sequence->picture_width;
+ }
+ if ( m->info->sequence->picture_height < m->info->sequence->height )
+ {
+ crop[1] = m->info->sequence->height - m->info->sequence->picture_height;
+ }
+
src_w = width - (crop[2] + crop[3]);
src_h = height - (crop[0] + crop[1]);
if ( job )
@@ -280,7 +301,7 @@ static hb_buffer_t *hb_copy_frame( hb_job_t *job, int width, int height,
}
hb_buffer_t *buf = hb_video_buffer_init( dst_w, dst_h );
- buf->start = -1;
+ buf->s.start = -1;
AVPicture in, out, pic_crop;
@@ -290,23 +311,34 @@ static hb_buffer_t *hb_copy_frame( hb_job_t *job, int width, int height,
in.linesize[0] = width;
in.linesize[1] = width>>1;
in.linesize[2] = width>>1;
- avpicture_fill( &out, buf->data, PIX_FMT_YUV420P, dst_w, dst_h );
+ hb_avpicture_fill( &out, buf );
av_picture_crop( &pic_crop, &in, pixfmt, crop[0], crop[2] );
- // Source and Dest dimensions may be the same. There is no speed
- // cost to using sws_scale to simply copy the data.
- struct SwsContext *context = hb_sws_get_context( src_w, src_h, pixfmt,
- dst_w, dst_h, PIX_FMT_YUV420P,
- SWS_LANCZOS|SWS_ACCURATE_RND);
- if ( context == NULL )
+ if ( !m->sws_context ||
+ m->sws_width != src_w ||
+ m->sws_height != src_h ||
+ m->sws_pix_fmt != pixfmt )
{
- hb_buffer_close( &buf );
- return NULL;
+ // Source and Dest dimensions may be the same. There is no speed
+ // cost to using sws_scale to simply copy the data.
+ m->sws_context = hb_sws_get_context( src_w, src_h, pixfmt,
+ dst_w, dst_h, buf->f.fmt,
+ SWS_LANCZOS|SWS_ACCURATE_RND);
+ m->sws_width = src_w;
+ m->sws_height = src_h;
+ m->sws_pix_fmt = pixfmt;
+
+ if ( m->sws_context == NULL )
+ {
+ hb_buffer_close( &buf );
+ return NULL;
+ }
+
}
- sws_scale( context, (const uint8_t* const *)pic_crop.data, pic_crop.linesize, 0, src_h, out.data, out.linesize );
- sws_freeContext( context );
+ sws_scale( m->sws_context, (const uint8_t* const *)pic_crop.data,
+ pic_crop.linesize, 0, src_h, out.data, out.linesize );
return buf;
}
@@ -325,7 +357,7 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
if ( buf_es->size )
{
/* Feed libmpeg2 */
- if( buf_es->start >= 0 )
+ if( buf_es->s.start >= 0 )
{
next_tag( m, buf_es );
}
@@ -353,7 +385,7 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
if (m->tags[m->cur_tag].cc_buf)
{
hb_log("mpeg2 tag botch2: pts %"PRId64", tag pts %"PRId64" buf 0x%p",
- buf_es->start, m->tags[m->cur_tag].start, m->tags[m->cur_tag].cc_buf);
+ buf_es->s.start, m->tags[m->cur_tag].start, m->tags[m->cur_tag].cc_buf);
hb_buffer_close( &m->tags[m->cur_tag].cc_buf );
}
// see if we already made a tag for the timestamp. If so we
@@ -416,23 +448,7 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
if( m->got_iframe )
{
- int crop[4] = {0};
- if ( m->info->sequence->picture_width < m->info->sequence->width )
- {
- crop[3] = m->info->sequence->width - m->info->sequence->picture_width;
- }
- if ( m->info->sequence->picture_height < m->info->sequence->height )
- {
- crop[1] = m->info->sequence->height - m->info->sequence->picture_height;
- }
- buf = hb_copy_frame( m->job,
- m->info->sequence->width,
- m->info->sequence->height,
- crop,
- m->pixfmt,
- m->info->display_fbuf->buf[0],
- m->info->display_fbuf->buf[1],
- m->info->display_fbuf->buf[2] );
+ buf = hb_copy_frame( m );
if ( buf == NULL )
continue;
@@ -442,29 +458,29 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
if( m->info->display_picture->flags & PIC_FLAG_TAGS )
{
int t = m->info->display_picture->tag;
- buf->start = m->tags[t].start;
+ buf->s.start = m->tags[t].start;
cc_buf = m->tags[t].cc_buf;
m->tags[t].start = -1;
m->tags[t].cc_buf = NULL;
}
- if( buf->start < 0 && m->last_pts >= 0 )
+ if( buf->s.start < 0 && m->last_pts >= 0 )
{
/* For some reason nb_fields is sometimes 1 while it
should be 2 */
- buf->start = m->last_pts +
+ buf->s.start = m->last_pts +
MAX( 2, m->info->display_picture->nb_fields ) *
m->info->sequence->frame_period / 600;
}
- if ( buf->start >= 0 )
+ if ( buf->s.start >= 0 )
{
- m->last_pts = buf->start;
+ m->last_pts = buf->s.start;
}
// if we were accumulating captions we now know the timestamp
// so ship them to the decoder.
if ( cc_buf )
{
- cc_buf->start = m->last_pts;
+ cc_buf->s.start = m->last_pts;
cc_send_to_decoder( m, cc_buf );
}
@@ -473,31 +489,35 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
{
// we were waiting for an iframe to insert a chapter mark
// and we have one.
- buf->new_chap = m->look_for_iframe;
+ int new_chap = m->look_for_iframe;
+ buf->s.new_chap = new_chap;
+
m->look_for_iframe = 0;
const char *chap_name = "";
- if ( m->job && buf->new_chap > 0 &&
+ if ( m->job && new_chap > 0 &&
hb_list_item( m->job->title->list_chapter,
- buf->new_chap - 1 ) )
+ new_chap - 1 ) )
{
- hb_chapter_t * c = hb_list_item( m->job->title->list_chapter,
- buf->new_chap - 1 );
+ hb_chapter_t * c = hb_list_item(
+ m->job->title->list_chapter,
+ new_chap - 1 );
chap_name = c->title;
}
hb_log( "mpeg2: \"%s\" (%d) at frame %u time %"PRId64,
- chap_name, buf->new_chap, m->nframes, buf->start );
+ chap_name, new_chap,
+ m->nframes, buf->s.start );
}
else if ( m->nframes == 0 )
{
// this is the first frame returned by the decoder
- m->first_pts = buf->start;
+ m->first_pts = buf->s.start;
if ( m->job && hb_list_item( m->job->title->list_chapter,
m->job->chapter_start - 1 ) )
{
hb_chapter_t * c = hb_list_item( m->job->title->list_chapter,
m->job->chapter_start - 1 );
hb_log( "mpeg2: \"%s\" (%d) at frame %u time %"PRId64,
- c->title, m->job->chapter_start, m->nframes, buf->start );
+ c->title, m->job->chapter_start, m->nframes, buf->s.start );
}
}
++m->nframes;
@@ -505,7 +525,7 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
m->flag = m->info->display_picture->flags;
/* Uncomment this block to see frame-by-frame picture flags, as the video encodes.
- hb_log("***** MPEG 2 Picture Info for PTS %"PRId64" *****", buf->start);
+ hb_log("***** MPEG 2 Picture Info for PTS %"PRId64" *****", buf->s.start);
if( m->flag & TOP_FIRST )
hb_log("MPEG2 Flag: Top field first");
if( m->flag & PROGRESSIVE )
@@ -584,12 +604,11 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
}
if ( (m->cadence[2] <= TB) && (m->cadence[1] <= TB) && (m->cadence[0] > TB) && (m->cadence[11]) )
- hb_log("%fs: Video -> Film", (float)buf->start / 90000);
+ hb_log("%fs: Video -> Film", (float)buf->s.start / 90000);
if ( (m->cadence[2] > TB) && (m->cadence[1] <= TB) && (m->cadence[0] <= TB) && (m->cadence[11]) )
- hb_log("%fs: Film -> Video", (float)buf->start / 90000);
+ hb_log("%fs: Film -> Video", (float)buf->s.start / 90000);
- /* Store picture flags for later use by filters */
- buf->flags = m->info->display_picture->flags;
+ buf->s.flags = m->info->display_picture->flags;
hb_list_add( list_raw, buf );
}
@@ -667,6 +686,11 @@ static void hb_libmpeg2_close( hb_libmpeg2_t ** _m )
mpeg2_close( m->libmpeg2 );
+ if ( m->sws_context )
+ {
+ sws_freeContext( m->sws_context );
+ }
+
int i;
for ( i = 0; i < NTAGS; ++i )
{
@@ -754,6 +778,7 @@ static int decmpeg2Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
{
hb_work_private_t * pv = w->private_data;
hb_buffer_t * buf, * last = NULL;
+ hb_buffer_t * in = *buf_in;
int status = HB_WORK_OK;
if( w->title && pv && pv->libmpeg2 && !pv->libmpeg2->title ) {
@@ -763,21 +788,21 @@ static int decmpeg2Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
// The reader found a chapter break. Remove it from the input
// stream. If we're reading (as opposed to scanning) start looking
// for the next GOP start since that's where the chapter begins.
- if( (*buf_in)->new_chap )
+ if( in->s.new_chap )
{
if ( pv->libmpeg2->job )
{
- pv->libmpeg2->look_for_break = (*buf_in)->new_chap;
+ pv->libmpeg2->look_for_break = in->s.new_chap;
}
- (*buf_in)->new_chap = 0;
+ in->s.new_chap = 0;
}
- hb_libmpeg2_decode( pv->libmpeg2, *buf_in, pv->list );
+ hb_libmpeg2_decode( pv->libmpeg2, in, pv->list );
/* if we got an empty buffer signaling end-of-stream send it downstream */
- if ( (*buf_in)->size == 0 )
+ if ( in->size == 0 )
{
- hb_list_add( pv->list, *buf_in );
+ hb_list_add( pv->list, in );
*buf_in = NULL;
status = HB_WORK_DONE;