Merge master.
[dcpomatic.git] / src / lib / ffmpeg.cc
1 /*
2     Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 extern "C" {
21 #include <libavcodec/avcodec.h>
22 #include <libavformat/avformat.h>
23 #include <libswscale/swscale.h>
24 #include <libpostproc/postprocess.h>
25 }
26 #include "ffmpeg.h"
27 #include "ffmpeg_content.h"
28 #include "exceptions.h"
29
30 #include "i18n.h"
31
32 using std::string;
33 using std::cout;
34 using std::stringstream;
35 using boost::shared_ptr;
36 using boost::lexical_cast;
37
38 boost::mutex FFmpeg::_mutex;
39
40 FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c)
41         : _ffmpeg_content (c)
42         , _avio_buffer (0)
43         , _avio_buffer_size (4096)
44         , _avio_context (0)
45         , _format_context (0)
46         , _frame (0)
47         , _video_stream (-1)
48 {
49         setup_general ();
50         setup_video ();
51         setup_audio ();
52 }
53
54 FFmpeg::~FFmpeg ()
55 {
56         boost::mutex::scoped_lock lm (_mutex);
57
58         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
59                 AVCodecContext* context = _format_context->streams[i]->codec;
60                 if (context->codec_type == AVMEDIA_TYPE_VIDEO || context->codec_type == AVMEDIA_TYPE_AUDIO) {
61                         avcodec_close (context);
62                 }
63         }
64
65         avcodec_free_frame (&_frame);
66         
67         avformat_close_input (&_format_context);
68 }
69
70 static int
71 avio_read_wrapper (void* data, uint8_t* buffer, int amount)
72 {
73         return reinterpret_cast<FFmpeg*>(data)->avio_read (buffer, amount);
74 }
75
76 static int64_t
77 avio_seek_wrapper (void* data, int64_t offset, int whence)
78 {
79         return reinterpret_cast<FFmpeg*>(data)->avio_seek (offset, whence);
80 }
81
82 void
83 FFmpeg::setup_general ()
84 {
85         av_register_all ();
86
87         _file_group.set_paths (_ffmpeg_content->paths ());
88         _avio_buffer = static_cast<uint8_t*> (av_malloc (_avio_buffer_size));
89         _avio_context = avio_alloc_context (_avio_buffer, _avio_buffer_size, 0, this, avio_read_wrapper, 0, avio_seek_wrapper);
90         _format_context = avformat_alloc_context ();
91         _format_context->pb = _avio_context;
92         
93         AVDictionary* options = 0;
94         /* These durations are in microseconds, and represent how far into the content file
95            we will look for streams.
96         */
97         av_dict_set (&options, "analyzeduration", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
98         av_dict_set (&options, "probesize", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
99         
100         if (avformat_open_input (&_format_context, 0, 0, &options) < 0) {
101                 throw OpenFileError (_ffmpeg_content->path(0).string ());
102         }
103
104         if (avformat_find_stream_info (_format_context, 0) < 0) {
105                 throw DecodeError (_("could not find stream information"));
106         }
107
108         /* Find video stream */
109
110         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
111                 AVStream* s = _format_context->streams[i];
112                 if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
113                         _video_stream = i;
114                 }
115         }
116
117         if (_video_stream < 0) {
118                 throw DecodeError (N_("could not find video stream"));
119         }
120
121         _frame = avcodec_alloc_frame ();
122         if (_frame == 0) {
123                 throw DecodeError (N_("could not allocate frame"));
124         }
125 }
126
127 void
128 FFmpeg::setup_video ()
129 {
130         boost::mutex::scoped_lock lm (_mutex);
131         
132         AVCodecContext* context = _format_context->streams[_video_stream]->codec;
133         AVCodec* codec = avcodec_find_decoder (context->codec_id);
134
135         if (codec == 0) {
136                 throw DecodeError (_("could not find video decoder"));
137         }
138
139         if (avcodec_open2 (context, codec, 0) < 0) {
140                 throw DecodeError (N_("could not open video decoder"));
141         }
142 }
143
144 void
145 FFmpeg::setup_audio ()
146 {
147         boost::mutex::scoped_lock lm (_mutex);
148
149         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
150                 AVCodecContext* context = _format_context->streams[i]->codec;
151                 if (context->codec_type != AVMEDIA_TYPE_AUDIO) {
152                         continue;
153                 }
154                 
155                 AVCodec* codec = avcodec_find_decoder (context->codec_id);
156                 if (codec == 0) {
157                         throw DecodeError (_("could not find audio decoder"));
158                 }
159                 
160                 if (avcodec_open2 (context, codec, 0) < 0) {
161                         throw DecodeError (N_("could not open audio decoder"));
162                 }
163         }
164 }
165
166
167 AVCodecContext *
168 FFmpeg::video_codec_context () const
169 {
170         return _format_context->streams[_video_stream]->codec;
171 }
172
173 AVCodecContext *
174 FFmpeg::audio_codec_context () const
175 {
176         return _ffmpeg_content->audio_stream()->stream(_format_context)->codec;
177 }
178
179 int
180 FFmpeg::avio_read (uint8_t* buffer, int const amount)
181 {
182         return _file_group.read (buffer, amount);
183 }
184
185 int64_t
186 FFmpeg::avio_seek (int64_t const pos, int whence)
187 {
188         if (whence == AVSEEK_SIZE) {
189                 return _file_group.length ();
190         }
191         
192         return _file_group.seek (pos, whence);
193 }