summaryrefslogtreecommitdiffstats
path: root/libhb/stream.c
diff options
context:
space:
mode:
authorvan <[email protected]>2008-09-11 04:05:04 +0000
committervan <[email protected]>2008-09-11 04:05:04 +0000
commit3053f495fe52dcdd38db2b104d2ea392dfc6761e (patch)
treea84470359a66888a918581708fecce53bc78f384 /libhb/stream.c
parentb9fb350aea3bb37349f24d6b33341b2644407588 (diff)
Various fixes for ffmpeg input files (mp4, avi, mkv, etc.):
- always use source time stamps (HB vfr mpeg4 files now handled correctly) - handle Microsoft's braindead "VFW packed b-frames" - compute average video frame rate from total duration & number of frames (ignore ffmpeg's frame rate which is closer to a max f.r. for vfr video). - workaround an ffmpeg audio decode abort when it used SSE instructions on unaligned buffers. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1687 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/stream.c')
-rwxr-xr-xlibhb/stream.c86
1 files changed, 65 insertions, 21 deletions
diff --git a/libhb/stream.c b/libhb/stream.c
index 930af3072..9768d959d 100755
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -4,15 +4,16 @@
Homepage: <http://handbrake.fr/>.
It may be used under the terms of the GNU General Public License. */
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
#include "hb.h"
#include "lang.h"
#include "a52dec/a52.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
-#include <string.h>
-#include <ctype.h>
-
#define min(a, b) a < b ? a : b
/*
@@ -136,6 +137,8 @@ struct hb_stream_s
hb_title_t *title;
AVFormatContext *ffmpeg_ic;
+ AVPacket *ffmpeg_pkt;
+ double ffmpeg_tsconv[MAX_STREAMS];
struct {
int lang_code;
@@ -2337,6 +2340,9 @@ static int ffmpeg_codec_param( hb_stream_t *stream, int stream_index )
// (the original scan stream was closed and no longer exists).
static void ffmpeg_remap_stream( hb_stream_t *stream, hb_title_t *title )
{
+ // tell ffmpeg we want a pts on every frame it returns
+ stream->ffmpeg_ic->flags |= AVFMT_FLAG_GENPTS;
+
// all the video & audio came from the same stream so remapping
// the video's stream slot takes care of everything.
int slot = title->video_codec_param & (ffmpeg_sl_size - 1);
@@ -2392,6 +2398,8 @@ static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title )
stream->ffmpeg_ic = ic;
stream->hb_stream_type = ffmpeg;
+ stream->ffmpeg_pkt = malloc(sizeof(*stream->ffmpeg_pkt));
+ av_init_packet( stream->ffmpeg_pkt );
if ( title )
{
@@ -2440,6 +2448,11 @@ static void ffmpeg_close( hb_stream_t *d )
av_close_input_file( ffmpeg_deferred_close );
}
ffmpeg_deferred_close = d->ffmpeg_ic;
+ if ( d->ffmpeg_pkt != NULL )
+ {
+ free( d->ffmpeg_pkt );
+ d->ffmpeg_pkt = NULL;
+ }
}
static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id )
@@ -2561,27 +2574,58 @@ static int64_t av_to_hb_pts( int64_t pts, double conv_factor )
static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf )
{
- AVPacket pkt;
+ int err;
+ if ( ( err = av_read_frame( stream->ffmpeg_ic, stream->ffmpeg_pkt )) < 0 )
+ {
+ // XXX the following conditional is to handle avi files that
+ // use M$ 'packed b-frames' and occasionally have negative
+ // sizes for the null frames these require.
+ if ( err != AVERROR_NOMEM || stream->ffmpeg_pkt->size >= 0 )
+ // eof
+ return 0;
+ }
+ if ( stream->ffmpeg_pkt->size <= 0 )
+ {
+ // M$ "invalid and inefficient" packed b-frames require 'null frames'
+ // following them to preserve the timing (since the packing puts two
+ // or more frames in what looks like one avi frame). The contents and
+ // size of these null frames are ignored by the ff_h263_decode_frame
+ // as long as they're < 20 bytes. We need a positive size so we use
+ // one byte if we're given a zero or negative size. We don't know
+ // if the pkt data points anywhere reasonable so we just stick a
+ // byte of zero in our outbound buf.
+ buf->size = 1;
+ *buf->data = 0;
+ }
+ else
+ {
+ if ( stream->ffmpeg_pkt->size > buf->alloc )
+ {
+ // need to expand buffer
+ hb_buffer_realloc( buf, stream->ffmpeg_pkt->size );
+ }
+ memcpy( buf->data, stream->ffmpeg_pkt->data, stream->ffmpeg_pkt->size );
+ buf->size = stream->ffmpeg_pkt->size;
+ }
+ buf->id = stream->ffmpeg_pkt->stream_index;
- if ( av_read_frame( stream->ffmpeg_ic, &pkt ) < 0 )
+ // if we haven't done it already, compute a conversion factor to go
+ // from the ffmpeg timebase for the stream to HB's 90KHz timebase.
+ double tsconv = stream->ffmpeg_tsconv[stream->ffmpeg_pkt->stream_index];
+ if ( ! tsconv )
{
- return 0;
+ AVStream *s = stream->ffmpeg_ic->streams[stream->ffmpeg_pkt->stream_index];
+ tsconv = 90000. * (double)s->time_base.num / (double)s->time_base.den;
+ stream->ffmpeg_tsconv[stream->ffmpeg_pkt->stream_index] = tsconv;
+ }
+
+ buf->start = av_to_hb_pts( stream->ffmpeg_pkt->pts, tsconv );
+ buf->renderOffset = av_to_hb_pts( stream->ffmpeg_pkt->dts, tsconv );
+ if ( buf->renderOffset >= 0 && buf->start == -1 )
+ {
+ buf->start = buf->renderOffset;
}
- if ( pkt.size > buf->alloc )
- {
- // need to expand buffer
- hb_buffer_realloc( buf, pkt.size );
- }
- memcpy( buf->data, pkt.data, pkt.size );
- buf->id = pkt.stream_index;
- buf->size = pkt.size;
- int64_t pts = pkt.pts != AV_NOPTS_VALUE? pkt.pts :
- pkt.dts != AV_NOPTS_VALUE? pkt.dts : -1;
- buf->start = av_to_hb_pts( pts,
- av_q2d(stream->ffmpeg_ic->streams[pkt.stream_index]->time_base)*90000. );
- buf->renderOffset = av_to_hb_pts( pkt.pts,
- av_q2d(stream->ffmpeg_ic->streams[pkt.stream_index]->time_base)*90000. );
- av_free_packet( &pkt );
+ av_free_packet( stream->ffmpeg_pkt );
return 1;
}