/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <iomanip>
#include <iostream>
#include <stdint.h>
-#include <boost/lexical_cast.hpp>
#include <sndfile.h>
extern "C" {
#include <libavcodec/avcodec.h>
using boost::dynamic_pointer_cast;
using dcp::Size;
-FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log> log, bool video, bool audio, bool subtitles)
+FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log> log)
: VideoDecoder (c)
, AudioDecoder (c)
, FFmpeg (c)
, _log (log)
, _subtitle_codec_context (0)
, _subtitle_codec (0)
- , _decode_video (video)
- , _decode_audio (audio)
- , _decode_subtitles (subtitles)
- , _pts_offset (0)
{
setup_subtitle ();
We will do pts_to_use = pts_from_ffmpeg + pts_offset;
*/
- bool const have_video = video && c->first_video();
- bool const have_audio = _decode_audio && c->audio_stream () && c->audio_stream()->first_audio;
+ bool const have_video = c->first_video();
+ bool const have_audio = c->audio_stream () && c->audio_stream()->first_audio;
/* First, make one of them start at 0 */
/* XXX: should we reset _packet.data and size after each *_decode_* call? */
- if (_decode_video) {
- while (decode_video_packet ()) {}
- }
+ while (decode_video_packet ()) {}
- if (_ffmpeg_content->audio_stream() && _decode_audio) {
+ if (_ffmpeg_content->audio_stream()) {
decode_audio_packet ();
AudioDecoder::flush ();
}
int const si = _packet.stream_index;
- if (si == _video_stream && _decode_video) {
+ if (si == _video_stream) {
decode_video_packet ();
- } else if (_ffmpeg_content->audio_stream() && _ffmpeg_content->audio_stream()->uses_index (_format_context, si) && _decode_audio) {
+ } else if (_ffmpeg_content->audio_stream() && _ffmpeg_content->audio_stream()->uses_index (_format_context, si)) {
decode_audio_packet ();
- } else if (_ffmpeg_content->subtitle_stream() && _ffmpeg_content->subtitle_stream()->uses_index (_format_context, si) && _decode_subtitles) {
+ } else if (_ffmpeg_content->subtitle_stream() && _ffmpeg_content->subtitle_stream()->uses_index (_format_context, si)) {
decode_subtitle_packet ();
}
avcodec_get_frame_defaults (_frame);
- int finished = 0;
- r = avcodec_decode_video2 (video_codec_context(), _frame, &finished, &_packet);
- if (r >= 0 && finished) {
+ int got_picture = 0;
+ r = avcodec_decode_video2 (video_codec_context(), _frame, &got_picture, &_packet);
+ if (r >= 0 && got_picture) {
last_video = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base) + _pts_offset;
}
AVPacket copy_packet = _packet;
while (copy_packet.size > 0) {
- int finished;
- r = avcodec_decode_audio4 (audio_codec_context(), _frame, &finished, &_packet);
- if (r >= 0 && finished) {
+ int got_frame;
+ r = avcodec_decode_audio4 (audio_codec_context(), _frame, &got_frame, &_packet);
+ if (r >= 0 && got_frame) {
last_audio = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base) + _pts_offset;
}
void
FFmpegDecoder::seek (ContentTime time, bool accurate)
{
- Decoder::seek (time, accurate);
- if (_decode_audio) {
- AudioDecoder::seek (time, accurate);
- }
+ VideoDecoder::seek (time, accurate);
+ AudioDecoder::seek (time, accurate);
- /* If we are doing an accurate seek, our initial shot will be 200ms (200 being
+ /* If we are doing an accurate seek, our initial shot will be 2s (2 being
a number plucked from the air) earlier than we want to end up. The loop below
will hopefully then step through to where we want to be.
*/
- ContentTime pre_roll = accurate ? ContentTime::from_seconds (0.2) : ContentTime (0);
+ ContentTime pre_roll = accurate ? ContentTime::from_seconds (2) : ContentTime (0);
ContentTime initial_seek = time - pre_roll;
if (initial_seek < ContentTime (0)) {
initial_seek = ContentTime (0);
list<pair<shared_ptr<Image>, int64_t> > images = graph->process (_frame);
- string post_process = Filter::ffmpeg_strings (_ffmpeg_content->filters()).second;
-
for (list<pair<shared_ptr<Image>, int64_t> >::iterator i = images.begin(); i != images.end(); ++i) {
shared_ptr<Image> image = i->first;
- if (!post_process.empty ()) {
- image = image->post_process (post_process, true);
- }
if (i->second != AV_NOPTS_VALUE) {
- video (image, false, ContentTime::from_seconds (i->second * av_q2d (_format_context->streams[_video_stream]->time_base)) + _pts_offset);
+ double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset.seconds ();
+ video (image, rint (pts * _ffmpeg_content->video_frame_rate ()));
} else {
_log->log ("Dropping frame without PTS");
}
indicate that the previous subtitle should stop.
*/
if (sub.num_rects <= 0) {
- image_subtitle (shared_ptr<Image> (), dcpomatic::Rect<double> (), ContentTime (), ContentTime ());
+ image_subtitle (ContentTime (), ContentTime (), shared_ptr<Image> (), dcpomatic::Rect<double> ());
return;
} else if (sub.num_rects > 1) {
throw DecodeError (_("multi-part subtitles not yet supported"));
AVSubtitleRect const * rect = sub.rects[0];
if (rect->type != SUBTITLE_BITMAP) {
- throw DecodeError (_("non-bitmap subtitles not yet supported"));
+ /* XXX */
+ // throw DecodeError (_("non-bitmap subtitles not yet supported"));
+ return;
}
/* Note RGBA is expressed little-endian, so the first byte in the word is R, second
dcp::Size const vs = _ffmpeg_content->video_size ();
image_subtitle (
+ from,
+ to,
image,
dcpomatic::Rect<double> (
static_cast<double> (rect->x) / vs.width,
static_cast<double> (rect->y) / vs.height,
static_cast<double> (rect->w) / vs.width,
static_cast<double> (rect->h) / vs.height
- ),
- from,
- to
+ )
);
-
avsubtitle_free (&sub);
}