--- /dev/null
+creator: Carl Hetherington <cth@carlh.net>
+
+
+reporter: Carl Hetherington <cth@carlh.net>
+
+
+severity: minor
+
+
+status: open
+
+
+summary: Do the delay line in deinterleaved floats to simplify code.
+
+
+time: Mon, 22 Oct 2012 13:27:50 +0000
+
--- /dev/null
+creator: Carl Hetherington <cth@carlh.net>
+
+
+reporter: Carl Hetherington <cth@carlh.net>
+
+
+severity: minor
+
+
+status: open
+
+
+summary: Decoder should use its own methods more than FilmState
+
+
+time: Mon, 22 Oct 2012 13:28:57 +0000
+
void
Decoder::process_begin ()
{
- _delay_in_bytes = _fs->total_audio_delay() * _fs->audio_sample_rate() * _fs->audio_channels() * bytes_per_audio_sample() / 1000;
+ _delay_in_bytes = _fs->audio_delay() * _fs->audio_sample_rate() * _fs->audio_channels() * bytes_per_audio_sample() / 1000;
delete _delay_line;
_delay_line = new DelayLine (_delay_in_bytes);
- _log->log (String::compose ("Decoding audio with total delay of %1", _fs->total_audio_delay()));
-
_audio_frames_processed = 0;
}
_log->log (String::compose ("DCP length is %1; %2 frames of audio processed.", _fs->dcp_length(), _audio_frames_processed));
_log->log (String::compose ("Adding %1 frames of silence to the end.", audio_short_by_frames));
+ /* XXX: this is slightly questionable; does memset () give silence with all
+ sample formats?
+ */
+
int64_t bytes = audio_short_by_frames * _fs->audio_channels() * bytes_per_audio_sample();
int64_t const silence_size = 16 * 1024 * _fs->audio_channels() * bytes_per_audio_sample();
virtual int64_t audio_channel_layout () const = 0;
virtual bool has_subtitles () const = 0;
- /** @return amount of extra unwanted audio at the start (or -ve for unwanted video) in milliseconds */
- virtual int audio_to_discard () const {
- return 0;
- }
-
void process_begin ();
bool pass ();
void process_end ();
void process_audio (uint8_t *, int);
void process_subtitle (boost::shared_ptr<TimedSubtitle>);
+ int bytes_per_audio_sample () const;
+
/** our FilmState */
boost::shared_ptr<const FilmState> _fs;
/** our options */
private:
void setup_video_filters ();
void emit_audio (uint8_t* data, int size);
- int bytes_per_audio_sample () const;
/** last video frame to be processed */
int _video_frame;
fs->set_length (_decoder->last_video_frame ());
_log->log (String::compose ("Video length is %1 frames", _decoder->last_video_frame()));
- _log->log (String::compose ("%1ms of audio to discard", _decoder->audio_to_discard()));
ascend ();
{
return _decoder->last_video_frame ();
}
-
-int
-ExamineContentJob::audio_to_discard () const
-{
- return _decoder->audio_to_discard ();
-}
-
void run ();
int last_video_frame () const;
- int audio_to_discard () const;
private:
boost::shared_ptr<Decoder> _decoder;
, _subtitle_codec_context (0)
, _subtitle_codec (0)
, _first_video_pts (-1)
+ , _first_audio_pts (-1)
{
setup_general ();
setup_video ();
if (_packet.stream_index == _video_stream) {
+ if (_first_video_pts == -1) {
+ _first_video_pts = _packet.pts;
+ }
+
int frame_finished;
if (avcodec_decode_video2 (_video_codec_context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
- if (_first_video_pts == -1) {
- _first_video_pts = _packet.pts;
- }
process_video (_frame);
}
- } else if (_audio_stream >= 0 && _packet.stream_index == _audio_stream && _opt->decode_audio) {
-
+ } else if (_audio_stream >= 0 && _packet.stream_index == _audio_stream && _opt->decode_audio && (_first_video_pts != -1 && _packet.pts > _first_video_pts)) {
+
+ /* Note: We only decode audio if we've had our first video packet through, and if this
+ packet comes after it. Until then it is thrown away.
+ */
+
+ if (_first_audio_pts == -1) {
+ _first_audio_pts = _packet.pts;
+
+ /* This is our first audio packet, and if we've arrived here we must have had our
+ first video packet. Push some silence to make up the gap between our first
+ video packet and our first audio.
+ */
+
+ AVStream* v = _format_context->streams[_video_stream];
+ AVStream* a = _format_context->streams[_audio_stream];
+
+ assert (v->time_base.num == a->time_base.num);
+ assert (v->time_base.den == a->time_base.den);
+
+ /* samples of silence that we must push */
+ int const s = rint (av_q2d (v->time_base) * (_first_audio_pts - _first_video_pts) * audio_sample_rate ());
+
+ _log->log (
+ String::compose (
+ "First video at %1, first audio at %2, pushing %3 samples of silence",
+ _first_video_pts, _first_audio_pts, s
+ )
+ );
+
+ /* hence bytes */
+ int const b = s * audio_channels() * bytes_per_audio_sample();
+
+ /* XXX: this assumes that it won't be too much, and there are shaky assumptions
+ that all sound representations are silent with memset()ed zero data.
+ */
+ uint8_t silence[b];
+ memset (silence, 0, b);
+ process_audio (silence, b);
+ }
+
avcodec_get_frame_defaults (_frame);
int frame_finished;
return n.str ();
}
-int
-FFmpegDecoder::audio_to_discard () const
-{
- AVStream* v = _format_context->streams[_video_stream];
- AVStream* a = _format_context->streams[_audio_stream];
-
- assert (v->time_base.num == a->time_base.num);
- assert (v->time_base.den == a->time_base.den);
-
- return rint (av_q2d (v->time_base) * 1000 * (_first_video_pts - _first_audio_pts));
-}
AVSampleFormat audio_sample_format () const;
int64_t audio_channel_layout () const;
bool has_subtitles () const;
- int bytes_per_audio_sample () const;
- int audio_to_discard () const;
std::vector<AudioStream> audio_streams () const;
std::vector<SubtitleStream> subtitle_streams () const;
Film::examine_content_post_gui ()
{
set_length (_examine_content_job->last_video_frame ());
- set_audio_to_discard (_examine_content_job->audio_to_discard ());
_examine_content_job.reset ();
string const tdir = dir ("thumbs");
}
f << "frames_per_second " << _frames_per_second << "\n";
- f << "audio_to_discard " << _audio_to_discard << "\n";
_dirty = false;
}
_subtitle_streams.push_back (SubtitleStream (v));
} else if (k == "frames_per_second") {
_frames_per_second = atof (v.c_str ());
- } else if (k == "audio_to_discard") {
- _audio_to_discard = atoi (v.c_str ());
}
}
_frames_per_second = f;
signal_changed (FRAMES_PER_SECOND);
}
-
-void
-FilmState::set_audio_to_discard (int a)
-{
- _audio_to_discard = a;
- signal_changed (AUDIO_TO_DISCARD);
-}
void
FilmState::signal_changed (Property p)
return _audio_streams[_audio_stream].channels ();
}
-
-int
-FilmState::total_audio_delay () const
-{
- return _audio_delay - _audio_to_discard;
-}
, _audio_sample_rate (0)
, _has_subtitles (false)
, _frames_per_second (0)
- , _audio_to_discard (0)
, _dirty (false)
{}
, _audio_streams (o._audio_streams)
, _subtitle_streams (o._subtitle_streams)
, _frames_per_second (o._frames_per_second)
- , _audio_to_discard (o._audio_to_discard)
, _dirty (o._dirty)
{}
}
int audio_channels () const;
- int total_audio_delay () const;
enum Property {
NONE,
AUDIO_STREAMS,
SUBTITLE_STREAMS,
FRAMES_PER_SECOND,
- AUDIO_TO_DISCARD
};
return _frames_per_second;
}
- int audio_to_discard () const {
- return _audio_to_discard;
- }
-
/* SET */
void set_directory (std::string);
void set_audio_streams (std::vector<AudioStream>);
void set_subtitle_streams (std::vector<SubtitleStream>);
void set_frames_per_second (float);
- void set_audio_to_discard (int);
/** Emitted when some property has changed */
mutable sigc::signal1<void, Property> Changed;
std::vector<SubtitleStream> _subtitle_streams;
/** Frames per second of the source */
float _frames_per_second;
- /** Number of milliseconds of audio to discard at the start of this film
- in order to sync audio with video. Can be negative.
- */
- int _audio_to_discard;
mutable bool _dirty;