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