Merge master.
[dcpomatic.git] / src / lib / ffmpeg.cc
1 /*
2     Copyright (C) 2013-2014 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 }
25 #include <dcp/raw_convert.h>
26 #include "ffmpeg.h"
27 #include "ffmpeg_content.h"
28 #include "ffmpeg_audio_stream.h"
29 #include "ffmpeg_subtitle_stream.h"
30 #include "exceptions.h"
31 #include "util.h"
32
33 #include "i18n.h"
34
35 using std::string;
36 using std::cout;
37 using std::stringstream;
38 using boost::shared_ptr;
39 using dcp::raw_convert;
40
41 boost::mutex FFmpeg::_mutex;
42
43 FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c)
44         : _ffmpeg_content (c)
45         , _avio_buffer (0)
46         , _avio_buffer_size (4096)
47         , _avio_context (0)
48         , _format_context (0)
49         , _frame (0)
50         , _video_stream (-1)
51 {
52         setup_general ();
53         setup_decoders ();
54 }
55
56 FFmpeg::~FFmpeg ()
57 {
58         boost::mutex::scoped_lock lm (_mutex);
59
60         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
61                 avcodec_close (_format_context->streams[i]->codec);
62         }
63
64         av_frame_free (&_frame);
65         avformat_close_input (&_format_context);
66 }
67
68 static int
69 avio_read_wrapper (void* data, uint8_t* buffer, int amount)
70 {
71         return reinterpret_cast<FFmpeg*>(data)->avio_read (buffer, amount);
72 }
73
74 static int64_t
75 avio_seek_wrapper (void* data, int64_t offset, int whence)
76 {
77         return reinterpret_cast<FFmpeg*>(data)->avio_seek (offset, whence);
78 }
79
80 void
81 FFmpeg::setup_general ()
82 {
83         av_register_all ();
84
85         _file_group.set_paths (_ffmpeg_content->paths ());
86         _avio_buffer = static_cast<uint8_t*> (wrapped_av_malloc (_avio_buffer_size));
87         _avio_context = avio_alloc_context (_avio_buffer, _avio_buffer_size, 0, this, avio_read_wrapper, 0, avio_seek_wrapper);
88         _format_context = avformat_alloc_context ();
89         _format_context->pb = _avio_context;
90         
91         AVDictionary* options = 0;
92         /* These durations are in microseconds, and represent how far into the content file
93            we will look for streams.
94         */
95         av_dict_set (&options, "analyzeduration", raw_convert<string> (5 * 60 * 1000000).c_str(), 0);
96         av_dict_set (&options, "probesize", raw_convert<string> (5 * 60 * 1000000).c_str(), 0);
97         
98         if (avformat_open_input (&_format_context, 0, 0, &options) < 0) {
99                 throw OpenFileError (_ffmpeg_content->path(0).string ());
100         }
101
102         if (avformat_find_stream_info (_format_context, 0) < 0) {
103                 throw DecodeError (_("could not find stream information"));
104         }
105
106         /* Find video stream */
107
108         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
109                 AVStream* s = _format_context->streams[i];
110                 if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
111                         _video_stream = i;
112                 }
113         }
114
115         if (_video_stream < 0) {
116                 throw DecodeError (N_("could not find video stream"));
117         }
118
119         /* Hack: if the AVStreams have zero IDs, put some in.  We
120            use the IDs so that we can cope with VOBs, in which streams
121            move about in index but remain with the same ID in different
122            VOBs.  However, some files have all-zero IDs, hence this hack.
123         */
124            
125         uint32_t i = 0;
126         while (i < _format_context->nb_streams && _format_context->streams[i]->id == 0) {
127                 ++i;
128         }
129
130         if (i == _format_context->nb_streams) {
131                 /* Put in our own IDs */
132                 for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
133                         _format_context->streams[i]->id = i;
134                 }
135         }
136
137         _frame = av_frame_alloc ();
138         if (_frame == 0) {
139                 throw DecodeError (N_("could not allocate frame"));
140         }
141 }
142
143 void
144 FFmpeg::setup_decoders ()
145 {
146         boost::mutex::scoped_lock lm (_mutex);
147
148         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
149                 AVCodecContext* context = _format_context->streams[i]->codec;
150                 
151                 AVCodec* codec = avcodec_find_decoder (context->codec_id);
152                 if (codec) {
153                         if (avcodec_open2 (context, codec, 0) < 0) {
154                                 throw DecodeError (N_("could not open decoder"));
155                         }
156                 }
157
158                 /* We are silently ignoring any failures to find suitable decoders here */
159         }
160 }
161
162 AVCodecContext *
163 FFmpeg::video_codec_context () const
164 {
165         return _format_context->streams[_video_stream]->codec;
166 }
167
168 AVCodecContext *
169 FFmpeg::audio_codec_context () const
170 {
171         if (!_ffmpeg_content->audio_stream ()) {
172                 return 0;
173         }
174         
175         return _ffmpeg_content->audio_stream()->stream(_format_context)->codec;
176 }
177
178 AVCodecContext *
179 FFmpeg::subtitle_codec_context () const
180 {
181         if (!_ffmpeg_content->subtitle_stream ()) {
182                 return 0;
183         }
184         
185         return _ffmpeg_content->subtitle_stream()->stream(_format_context)->codec;
186 }
187
188 int
189 FFmpeg::avio_read (uint8_t* buffer, int const amount)
190 {
191         return _file_group.read (buffer, amount);
192 }
193
194 int64_t
195 FFmpeg::avio_seek (int64_t const pos, int whence)
196 {
197         if (whence == AVSEEK_SIZE) {
198                 return _file_group.length ();
199         }
200         
201         return _file_group.seek (pos, whence);
202 }