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