Move FFmpegStream classes into their own source files.
[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 "exceptions.h"
30 #include "util.h"
31
32 #include "i18n.h"
33
34 using std::string;
35 using std::cout;
36 using std::stringstream;
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_video ();
53         setup_audio ();
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                 AVCodecContext* context = _format_context->streams[i]->codec;
62                 if (context->codec_type == AVMEDIA_TYPE_VIDEO || context->codec_type == AVMEDIA_TYPE_AUDIO) {
63                         avcodec_close (context);
64                 }
65         }
66
67         av_frame_free (&_frame);
68         
69         avformat_close_input (&_format_context);
70 }
71
72 static int
73 avio_read_wrapper (void* data, uint8_t* buffer, int amount)
74 {
75         return reinterpret_cast<FFmpeg*>(data)->avio_read (buffer, amount);
76 }
77
78 static int64_t
79 avio_seek_wrapper (void* data, int64_t offset, int whence)
80 {
81         return reinterpret_cast<FFmpeg*>(data)->avio_seek (offset, whence);
82 }
83
84 void
85 FFmpeg::setup_general ()
86 {
87         av_register_all ();
88
89         _file_group.set_paths (_ffmpeg_content->paths ());
90         _avio_buffer = static_cast<uint8_t*> (wrapped_av_malloc (_avio_buffer_size));
91         _avio_context = avio_alloc_context (_avio_buffer, _avio_buffer_size, 0, this, avio_read_wrapper, 0, avio_seek_wrapper);
92         _format_context = avformat_alloc_context ();
93         _format_context->pb = _avio_context;
94         
95         AVDictionary* options = 0;
96         /* These durations are in microseconds, and represent how far into the content file
97            we will look for streams.
98         */
99         av_dict_set (&options, "analyzeduration", raw_convert<string> (5 * 60 * 1000000).c_str(), 0);
100         av_dict_set (&options, "probesize", raw_convert<string> (5 * 60 * 1000000).c_str(), 0);
101         
102         if (avformat_open_input (&_format_context, 0, 0, &options) < 0) {
103                 throw OpenFileError (_ffmpeg_content->path(0).string ());
104         }
105
106         if (avformat_find_stream_info (_format_context, 0) < 0) {
107                 throw DecodeError (_("could not find stream information"));
108         }
109
110         /* Find video stream */
111
112         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
113                 AVStream* s = _format_context->streams[i];
114                 if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
115                         _video_stream = i;
116                 }
117         }
118
119         if (_video_stream < 0) {
120                 throw DecodeError (N_("could not find video stream"));
121         }
122
123         /* Hack: if the AVStreams have zero IDs, put some in.  We
124            use the IDs so that we can cope with VOBs, in which streams
125            move about in index but remain with the same ID in different
126            VOBs.  However, some files have all-zero IDs, hence this hack.
127         */
128            
129         uint32_t i = 0;
130         while (i < _format_context->nb_streams && _format_context->streams[i]->id == 0) {
131                 ++i;
132         }
133
134         if (i == _format_context->nb_streams) {
135                 /* Put in our own IDs */
136                 for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
137                         _format_context->streams[i]->id = i;
138                 }
139         }
140
141         _frame = av_frame_alloc ();
142         if (_frame == 0) {
143                 throw DecodeError (N_("could not allocate frame"));
144         }
145 }
146
147 void
148 FFmpeg::setup_video ()
149 {
150         boost::mutex::scoped_lock lm (_mutex);
151
152         assert (_video_stream >= 0);
153         AVCodecContext* context = _format_context->streams[_video_stream]->codec;
154         AVCodec* codec = avcodec_find_decoder (context->codec_id);
155
156         if (codec == 0) {
157                 throw DecodeError (_("could not find video decoder"));
158         }
159
160         if (avcodec_open2 (context, codec, 0) < 0) {
161                 throw DecodeError (N_("could not open video decoder"));
162         }
163 }
164
165 void
166 FFmpeg::setup_audio ()
167 {
168         boost::mutex::scoped_lock lm (_mutex);
169
170         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
171                 AVCodecContext* context = _format_context->streams[i]->codec;
172                 if (context->codec_type != AVMEDIA_TYPE_AUDIO) {
173                         continue;
174                 }
175                 
176                 AVCodec* codec = avcodec_find_decoder (context->codec_id);
177                 if (codec == 0) {
178                         throw DecodeError (_("could not find audio decoder"));
179                 }
180                 
181                 if (avcodec_open2 (context, codec, 0) < 0) {
182                         throw DecodeError (N_("could not open audio decoder"));
183                 }
184         }
185 }
186
187
188 AVCodecContext *
189 FFmpeg::video_codec_context () const
190 {
191         return _format_context->streams[_video_stream]->codec;
192 }
193
194 AVCodecContext *
195 FFmpeg::audio_codec_context () const
196 {
197         if (!_ffmpeg_content->audio_stream ()) {
198                 return 0;
199         }
200         
201         return _ffmpeg_content->audio_stream()->stream(_format_context)->codec;
202 }
203
204 int
205 FFmpeg::avio_read (uint8_t* buffer, int const amount)
206 {
207         return _file_group.read (buffer, amount);
208 }
209
210 int64_t
211 FFmpeg::avio_seek (int64_t const pos, int whence)
212 {
213         if (whence == AVSEEK_SIZE) {
214                 return _file_group.length ();
215         }
216         
217         return _file_group.seek (pos, whence);
218 }