summaryrefslogtreecommitdiffstats
path: root/libmediafork/decmpeg2.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmediafork/decmpeg2.c')
-rw-r--r--libmediafork/decmpeg2.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/libmediafork/decmpeg2.c b/libmediafork/decmpeg2.c
new file mode 100644
index 000000000..e3188dfe2
--- /dev/null
+++ b/libmediafork/decmpeg2.c
@@ -0,0 +1,253 @@
+/* $Id: decmpeg2.c,v 1.12 2005/03/03 16:30:42 titer Exp $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.m0k.org/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#include "mediafork.h"
+
+#include "mpeg2dec/mpeg2.h"
+
+/**********************************************************************
+ * hb_libmpeg2_t
+ **********************************************************************
+ * A convenient libmpeg wrapper, used both here and in scan.c
+ *********************************************************************/
+struct hb_libmpeg2_s
+{
+ mpeg2dec_t * libmpeg2;
+ const mpeg2_info_t * info;
+ int width;
+ int height;
+ int rate;
+ int got_iframe;
+ int64_t last_pts;
+};
+
+/**********************************************************************
+ * hb_libmpeg2_init
+ **********************************************************************
+ *
+ *********************************************************************/
+hb_libmpeg2_t * hb_libmpeg2_init()
+{
+ hb_libmpeg2_t * m = calloc( sizeof( hb_libmpeg2_t ), 1 );
+
+ m->libmpeg2 = mpeg2_init();
+ m->info = mpeg2_info( m->libmpeg2 );
+ m->last_pts = -1;
+
+ return m;
+}
+
+/**********************************************************************
+ * hb_libmpeg2_decode
+ **********************************************************************
+ *
+ *********************************************************************/
+int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
+ hb_list_t * list_raw )
+{
+ mpeg2_state_t state;
+ hb_buffer_t * buf;
+ uint8_t * data;
+
+ /* Feed libmpeg2 */
+ if( buf_es->start > -1 )
+ {
+ mpeg2_tag_picture( m->libmpeg2, buf_es->start >> 32,
+ buf_es->start & 0xFFFFFFFF );
+ }
+ mpeg2_buffer( m->libmpeg2, buf_es->data,
+ buf_es->data + buf_es->size );
+
+ for( ;; )
+ {
+ state = mpeg2_parse( m->libmpeg2 );
+ if( state == STATE_BUFFER )
+ {
+ /* Require some more data */
+ break;
+ }
+ else if( state == STATE_SEQUENCE )
+ {
+ if( !( m->width && m->height && m->rate ) )
+ {
+ m->width = m->info->sequence->width;
+ m->height = m->info->sequence->height;
+ m->rate = m->info->sequence->frame_period;
+
+ if( m->rate == 900900 )
+ {
+ /* 29.97 fps. 3:2 pulldown might, or might not be
+ used. I can't find a way to know, so we always
+ output 23.976 */
+ m->rate = 1126125;
+ }
+ }
+ }
+ else if( ( state == STATE_SLICE || state == STATE_END ) &&
+ m->info->display_fbuf )
+ {
+ if( ( m->info->display_picture->flags &
+ PIC_MASK_CODING_TYPE ) == PIC_FLAG_CODING_TYPE_I )
+ {
+ m->got_iframe = 1;
+ }
+
+ if( m->got_iframe )
+ {
+ buf = hb_buffer_init( m->width * m->height * 3 / 2 );
+ data = buf->data;
+
+ memcpy( data, m->info->display_fbuf->buf[0],
+ m->width * m->height );
+ data += m->width * m->height;
+ memcpy( data, m->info->display_fbuf->buf[1],
+ m->width * m->height / 4 );
+ data += m->width * m->height / 4;
+ memcpy( data, m->info->display_fbuf->buf[2],
+ m->width * m->height / 4 );
+
+ if( m->info->display_picture->flags & PIC_FLAG_TAGS )
+ {
+ buf->start =
+ ( (uint64_t) m->info->display_picture->tag << 32 ) |
+ ( (uint64_t) m->info->display_picture->tag2 );
+ }
+ else if( m->last_pts > -1 )
+ {
+ /* For some reason nb_fields is sometimes 1 while it
+ should be 2 */
+ buf->start = m->last_pts +
+ MAX( 2, m->info->display_picture->nb_fields ) *
+ m->info->sequence->frame_period / 600;
+ }
+ else
+ {
+ buf->start = -1;
+ }
+ m->last_pts = buf->start;
+
+ hb_list_add( list_raw, buf );
+ }
+ }
+ else if( state == STATE_INVALID )
+ {
+ mpeg2_reset( m->libmpeg2, 0 );
+ }
+ }
+ return 1;
+}
+
+/**********************************************************************
+ * hb_libmpeg2_info
+ **********************************************************************
+ *
+ *********************************************************************/
+void hb_libmpeg2_info( hb_libmpeg2_t * m, int * width, int * height,
+ int * rate )
+{
+ *width = m->width;
+ *height = m->height;
+ *rate = m->rate;
+}
+
+/**********************************************************************
+ * hb_libmpeg2_close
+ **********************************************************************
+ *
+ *********************************************************************/
+void hb_libmpeg2_close( hb_libmpeg2_t ** _m )
+{
+ hb_libmpeg2_t * m = *_m;
+
+ mpeg2_close( m->libmpeg2 );
+
+ free( m );
+ *_m = NULL;
+}
+
+/**********************************************************************
+ * The decmpeg2 work object
+ **********************************************************************
+ *
+ *********************************************************************/
+struct hb_work_private_s
+{
+ hb_libmpeg2_t * libmpeg2;
+ hb_list_t * list;
+};
+
+/**********************************************************************
+ * hb_work_decmpeg2_init
+ **********************************************************************
+ *
+ *********************************************************************/
+int decmpeg2Init( hb_work_object_t * w, hb_job_t * job )
+{
+ hb_work_private_t * pv;
+
+ pv = calloc( 1, sizeof( hb_work_private_t ) );
+ w->private_data = pv;
+
+ pv->libmpeg2 = hb_libmpeg2_init();
+ pv->list = hb_list_init();
+
+ return 0;
+}
+
+/**********************************************************************
+ * Work
+ **********************************************************************
+ *
+ *********************************************************************/
+int decmpeg2Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
+ hb_buffer_t ** buf_out )
+{
+ hb_work_private_t * pv = w->private_data;
+ hb_buffer_t * buf, * last = NULL;
+
+ hb_libmpeg2_decode( pv->libmpeg2, *buf_in, pv->list );
+
+ *buf_out = NULL;
+ while( ( buf = hb_list_item( pv->list, 0 ) ) )
+ {
+ hb_list_rem( pv->list, buf );
+ if( last )
+ {
+ last->next = buf;
+ last = buf;
+ }
+ else
+ {
+ *buf_out = buf;
+ last = buf;
+ }
+ }
+
+ return HB_WORK_OK;
+}
+
+/**********************************************************************
+ * Close
+ **********************************************************************
+ *
+ *********************************************************************/
+void decmpeg2Close( hb_work_object_t * w )
+{
+ hb_work_private_t * pv = w->private_data;
+ hb_list_close( &pv->list );
+ hb_libmpeg2_close( &pv->libmpeg2 );
+ free( pv );
+}
+
+hb_work_object_t hb_decmpeg2 =
+{
+ WORK_DECMPEG2,
+ "MPEG-2 decoder (libmpeg2)",
+ decmpeg2Init,
+ decmpeg2Work,
+ decmpeg2Close
+};
+