Use FileGroup in FFmpeg.
[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 /** @param long_probe true to do a long probe of the file looking for streams */
41 FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c, bool long_probe)
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 (long_probe);
51         setup_video ();
52         setup_audio ();
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                 AVCodecContext* context = _format_context->streams[i]->codec;
61                 if (context->codec_type == AVMEDIA_TYPE_VIDEO || context->codec_type == AVMEDIA_TYPE_AUDIO) {
62                         avcodec_close (context);
63                 }
64         }
65
66         avcodec_free_frame (&_frame);
67         
68         avformat_close_input (&_format_context);
69 }
70
71 static int
72 avio_read_wrapper (void* data, uint8_t* buffer, int amount)
73 {
74         return reinterpret_cast<FFmpeg*>(data)->avio_read (buffer, amount);
75 }
76
77 static int64_t
78 avio_seek_wrapper (void* data, int64_t offset, int whence)
79 {
80         if (whence == AVSEEK_SIZE) {
81                 return reinterpret_cast<FFmpeg*>(data)->avio_length ();
82         }
83                         
84         return reinterpret_cast<FFmpeg*>(data)->avio_seek (offset, whence);
85 }
86
87 void
88 FFmpeg::setup_general (bool long_probe)
89 {
90         av_register_all ();
91
92         _file_group.set_paths (_ffmpeg_content->paths ());
93         _avio_buffer = static_cast<uint8_t*> (av_malloc (_avio_buffer_size));
94         _avio_context = avio_alloc_context (_avio_buffer, _avio_buffer_size, 0, this, avio_read_wrapper, 0, avio_seek_wrapper);
95         _format_context = avformat_alloc_context ();
96         _format_context->pb = _avio_context;
97         
98         AVDictionary* options = 0;
99         if (long_probe) {
100                 /* These durations are in microseconds, and represent how far into the content file
101                    we will look for streams.
102                 */
103                 av_dict_set (&options, "analyzeduration", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
104                 av_dict_set (&options, "probesize", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
105         }
106         
107         if (avformat_open_input (&_format_context, _ffmpeg_content->path(0).string().c_str(), 0, &options) < 0) {
108                 throw OpenFileError (_ffmpeg_content->path(0).string ());
109         }
110
111         if (avformat_find_stream_info (_format_context, 0) < 0) {
112                 throw DecodeError (_("could not find stream information"));
113         }
114
115         /* Find video stream */
116
117         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
118                 AVStream* s = _format_context->streams[i];
119                 if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
120                         _video_stream = i;
121                 }
122         }
123
124         if (_video_stream < 0) {
125                 throw DecodeError (N_("could not find video stream"));
126         }
127
128         _frame = avcodec_alloc_frame ();
129         if (_frame == 0) {
130                 throw DecodeError (N_("could not allocate frame"));
131         }
132 }
133
134 void
135 FFmpeg::setup_video ()
136 {
137         boost::mutex::scoped_lock lm (_mutex);
138         
139         AVCodecContext* context = _format_context->streams[_video_stream]->codec;
140         AVCodec* codec = avcodec_find_decoder (context->codec_id);
141
142         if (codec == 0) {
143                 throw DecodeError (_("could not find video decoder"));
144         }
145
146         if (avcodec_open2 (context, codec, 0) < 0) {
147                 throw DecodeError (N_("could not open video decoder"));
148         }
149 }
150
151 void
152 FFmpeg::setup_audio ()
153 {
154         boost::mutex::scoped_lock lm (_mutex);
155
156         for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
157                 AVCodecContext* context = _format_context->streams[i]->codec;
158                 if (context->codec_type != AVMEDIA_TYPE_AUDIO) {
159                         continue;
160                 }
161                 
162                 AVCodec* codec = avcodec_find_decoder (context->codec_id);
163                 if (codec == 0) {
164                         throw DecodeError (_("could not find audio decoder"));
165                 }
166                 
167                 if (avcodec_open2 (context, codec, 0) < 0) {
168                         throw DecodeError (N_("could not open audio decoder"));
169                 }
170         }
171 }
172
173
174 AVCodecContext *
175 FFmpeg::video_codec_context () const
176 {
177         return _format_context->streams[_video_stream]->codec;
178 }
179
180 AVCodecContext *
181 FFmpeg::audio_codec_context () const
182 {
183         return _format_context->streams[_ffmpeg_content->audio_stream()->id]->codec;
184 }
185
186 int
187 FFmpeg::avio_read (uint8_t* buffer, int const amount)
188 {
189         return _file_group.read (buffer, amount);
190 }
191
192 int64_t
193 FFmpeg::avio_seek (int64_t const pos, int whence)
194 {
195         return _file_group.seek (pos, whence);
196 }
197
198 int64_t
199 FFmpeg::avio_size ()
200 {
201         return _file_group.length ();
202 }