summaryrefslogtreecommitdiff
path: root/src/lib/ffmpeg_decoder.cc
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2012-07-15 00:14:28 +0100
committerCarl Hetherington <cth@carlh.net>2012-07-15 00:14:28 +0100
commitbb767c7e338414beee132af3e96829c1448e214b (patch)
treebec2858dcc7225a9bcc2acd8170c25508f6df6cb /src/lib/ffmpeg_decoder.cc
parent66c9be6bdb1361e5681e094a0c8170d268aa9518 (diff)
Move things round a bit.
Diffstat (limited to 'src/lib/ffmpeg_decoder.cc')
-rw-r--r--src/lib/ffmpeg_decoder.cc256
1 files changed, 256 insertions, 0 deletions
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
new file mode 100644
index 000000000..af258f381
--- /dev/null
+++ b/src/lib/ffmpeg_decoder.cc
@@ -0,0 +1,256 @@
+/*
+ Copyright (C) 2012 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/ffmpeg_decoder.cc
+ * @brief A decoder using FFmpeg to decode content.
+ */
+
+#include <stdexcept>
+#include <vector>
+#include <sstream>
+#include <iomanip>
+#include <iostream>
+#include <stdint.h>
+extern "C" {
+#include <tiffio.h>
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libswscale/swscale.h>
+#include <libpostproc/postprocess.h>
+}
+#include <sndfile.h>
+#include "film.h"
+#include "format.h"
+#include "transcoder.h"
+#include "job.h"
+#include "filter.h"
+#include "film_state.h"
+#include "options.h"
+#include "exceptions.h"
+#include "image.h"
+#include "util.h"
+#include "log.h"
+#include "ffmpeg_decoder.h"
+
+using namespace std;
+using namespace boost;
+
+FFmpegDecoder::FFmpegDecoder (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const Options> o, Job* j, Log* l, bool minimal, bool ignore_length)
+ : Decoder (s, o, j, l, minimal, ignore_length)
+ , _format_context (0)
+ , _video_stream (-1)
+ , _audio_stream (-1)
+ , _frame (0)
+ , _video_codec_context (0)
+ , _video_codec (0)
+ , _audio_codec_context (0)
+ , _audio_codec (0)
+{
+ setup_general ();
+ setup_video ();
+ setup_audio ();
+}
+
+FFmpegDecoder::~FFmpegDecoder ()
+{
+ if (_audio_codec_context) {
+ avcodec_close (_audio_codec_context);
+ }
+
+ if (_video_codec_context) {
+ avcodec_close (_video_codec_context);
+ }
+
+ av_free (_frame);
+ avformat_close_input (&_format_context);
+}
+
+void
+FFmpegDecoder::setup_general ()
+{
+ int r;
+
+ av_register_all ();
+
+ if ((r = avformat_open_input (&_format_context, _fs->content_path().c_str(), 0, 0)) != 0) {
+ throw OpenFileError (_fs->content_path ());
+ }
+
+ if (avformat_find_stream_info (_format_context, 0) < 0) {
+ throw DecodeError ("could not find stream information");
+ }
+
+ for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
+ if (_format_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ _video_stream = i;
+ } else if (_format_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ _audio_stream = i;
+ }
+ }
+
+ if (_video_stream < 0) {
+ throw DecodeError ("could not find video stream");
+ }
+ if (_audio_stream < 0) {
+ throw DecodeError ("could not find audio stream");
+ }
+
+ _frame = avcodec_alloc_frame ();
+ if (_frame == 0) {
+ throw DecodeError ("could not allocate frame");
+ }
+}
+
+void
+FFmpegDecoder::setup_video ()
+{
+ _video_codec_context = _format_context->streams[_video_stream]->codec;
+ _video_codec = avcodec_find_decoder (_video_codec_context->codec_id);
+
+ if (_video_codec == 0) {
+ throw DecodeError ("could not find video decoder");
+ }
+
+ if (avcodec_open2 (_video_codec_context, _video_codec, 0) < 0) {
+ throw DecodeError ("could not open video decoder");
+ }
+}
+
+void
+FFmpegDecoder::setup_audio ()
+{
+ _audio_codec_context = _format_context->streams[_audio_stream]->codec;
+ _audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id);
+
+ if (_audio_codec == 0) {
+ throw DecodeError ("could not find audio decoder");
+ }
+
+ if (avcodec_open2 (_audio_codec_context, _audio_codec, 0) < 0) {
+ throw DecodeError ("could not open audio decoder");
+ }
+}
+
+bool
+FFmpegDecoder::do_pass ()
+{
+ int r = av_read_frame (_format_context, &_packet);
+ if (r < 0) {
+ return true;
+ }
+
+ if (_packet.stream_index == _video_stream && _opt->decode_video) {
+
+ int frame_finished;
+ if (avcodec_decode_video2 (_video_codec_context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
+ process_video (_frame);
+ }
+
+ } else if (_packet.stream_index == _audio_stream && _opt->decode_audio) {
+
+ avcodec_get_frame_defaults (_frame);
+
+ int frame_finished;
+ if (avcodec_decode_audio4 (_audio_codec_context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
+ int const data_size = av_samples_get_buffer_size (
+ 0, _audio_codec_context->channels, _frame->nb_samples, audio_sample_format (), 1
+ );
+
+ process_audio (_frame->data[0], _audio_codec_context->channels, data_size);
+ }
+ }
+
+ av_free_packet (&_packet);
+ return false;
+}
+
+int
+FFmpegDecoder::length_in_frames () const
+{
+ return (_format_context->duration / AV_TIME_BASE) * frames_per_second ();
+}
+
+float
+FFmpegDecoder::frames_per_second () const
+{
+ return av_q2d (_format_context->streams[_video_stream]->avg_frame_rate);
+}
+
+int
+FFmpegDecoder::audio_channels () const
+{
+ if (_audio_codec_context == 0) {
+ return 0;
+ }
+
+ return _audio_codec_context->channels;
+}
+
+int
+FFmpegDecoder::audio_sample_rate () const
+{
+ if (_audio_codec_context == 0) {
+ return 0;
+ }
+
+ return _audio_codec_context->sample_rate;
+}
+
+AVSampleFormat
+FFmpegDecoder::audio_sample_format () const
+{
+ return _audio_codec_context->sample_fmt;
+}
+
+Size
+FFmpegDecoder::native_size () const
+{
+ return Size (_video_codec_context->width, _video_codec_context->height);
+}
+
+PixelFormat
+FFmpegDecoder::pixel_format () const
+{
+ return _video_codec_context->pix_fmt;
+}
+
+int
+FFmpegDecoder::time_base_numerator () const
+{
+ return _video_codec_context->time_base.num;
+}
+
+int
+FFmpegDecoder::time_base_denominator () const
+{
+ return _video_codec_context->time_base.den;
+}
+
+int
+FFmpegDecoder::sample_aspect_ratio_numerator () const
+{
+ return _video_codec_context->sample_aspect_ratio.num;
+}
+
+int
+FFmpegDecoder::sample_aspect_ratio_denominator () const
+{
+ return _video_codec_context->sample_aspect_ratio.den;
+}
+