~vanvugt/+junk/mediatomb

« back to all changes in this revision

Viewing changes to .pc/ffmpegthumbnailer-2.0.patch/src/metadata/ffmpeg_handler.cc

  • Committer: Bazaar Package Importer
  • Author(s): Lionel Le Folgoc
  • Date: 2010-02-22 20:16:31 UTC
  • mfrom: (4.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100222201631-fgwswo4s4ogdr8x8
Tags: 0.12.0~svn2018-6ubuntu1
* Merge from debian unstable, Ubuntu remaining changes:
  - Add OR depends on abrowser.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*MT*
 
2
    
 
3
    MediaTomb - http://www.mediatomb.cc/
 
4
    
 
5
    ffmpeg_handler.cc - this file is part of MediaTomb.
 
6
    
 
7
    Copyright (C) 2005 Gena Batyan <bgeradz@mediatomb.cc>,
 
8
                       Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>
 
9
    
 
10
    Copyright (C) 2006-2009 Gena Batyan <bgeradz@mediatomb.cc>,
 
11
                            Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>,
 
12
                            Leonhard Wimmer <leo@mediatomb.cc>
 
13
    
 
14
    MediaTomb is free software; you can redistribute it and/or modify
 
15
    it under the terms of the GNU General Public License version 2
 
16
    as published by the Free Software Foundation.
 
17
    
 
18
    MediaTomb is distributed in the hope that it will be useful,
 
19
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
21
    GNU General Public License for more details.
 
22
    
 
23
    You should have received a copy of the GNU General Public License
 
24
    version 2 along with MediaTomb; if not, write to the Free Software
 
25
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
26
    
 
27
    $Id: ffmpeg_handler.cc 2010 2009-01-11 19:10:43Z lww $
 
28
*/
 
29
/*
 
30
    This code was contributed by
 
31
    Copyright (C) 2007 Ingo Preiml <ipreiml@edu.uni-klu.ac.at>
 
32
*/
 
33
 
 
34
/// \file ffmpeg_handler.cc
 
35
/// \brief Implementeation of the FfmpegHandler class.
 
36
 
 
37
// Information about the stream are to be found in the structure
 
38
// AVFormatContext, defined in libavformat/avformat.h:335
 
39
// and in the structure
 
40
// AVCodecContext, defined in libavcodec/avcodec.h:722
 
41
// in the ffmpeg sources
 
42
 
 
43
#ifdef HAVE_CONFIG_H
 
44
    #include "autoconfig.h"
 
45
#endif
 
46
 
 
47
#ifdef HAVE_FFMPEG
 
48
 
 
49
// ffmpeg needs the following sources
 
50
// INT64_C is not defined in ffmpeg/avformat.h but is needed
 
51
// macro defines included via autoconfig.h
 
52
#include <stdint.h>
 
53
 
 
54
//#ifdef FFMPEG_NEEDS_EXTERN_C
 
55
extern "C" 
 
56
{
 
57
//#endif
 
58
 
 
59
#include AVFORMAT_INCLUDE
 
60
 
 
61
//#ifdef FFMPEG_NEEDS_EXTERN_C
 
62
} // extern "C"
 
63
//#endif
 
64
 
 
65
#ifdef HAVE_FFMPEGTHUMBNAILER
 
66
    #include <libffmpegthumbnailer/videothumbnailerc.h>
 
67
#endif
 
68
 
 
69
#include "config_manager.h"
 
70
#include "ffmpeg_handler.h"
 
71
#include "string_converter.h"
 
72
#include "common.h"
 
73
#include "tools.h"
 
74
#include "rexp.h"
 
75
//#include "mxml/mxml.h"
 
76
#include "mem_io_handler.h"
 
77
 
 
78
 
 
79
using namespace zmm;
 
80
//using namespace mxml;
 
81
 
 
82
// Default constructor
 
83
FfmpegHandler::FfmpegHandler() : MetadataHandler()
 
84
{
 
85
}
 
86
 
 
87
static void addFfmpegMetadataFields(Ref<CdsItem> item, AVFormatContext *pFormatCtx) 
 
88
{
 
89
 
 
90
        Ref<StringConverter> sc = StringConverter::m2i();
 
91
    
 
92
        if (strlen(pFormatCtx->title) > 0) 
 
93
    {
 
94
            log_debug("Added metadata title: %s\n", pFormatCtx->title);
 
95
        item->setMetadata(String(MT_KEYS[M_TITLE].upnp), 
 
96
                          sc->convert(String(pFormatCtx->title)));
 
97
        }
 
98
        if (strlen(pFormatCtx->author) > 0) 
 
99
    {
 
100
            log_debug("Added metadata author: %s\n", pFormatCtx->author);
 
101
        item->setMetadata(String(MT_KEYS[M_ARTIST].upnp), 
 
102
                          sc->convert(String(pFormatCtx->author)));
 
103
        }
 
104
        if (strlen(pFormatCtx->album) > 0) 
 
105
    {
 
106
            log_debug("Added metadata album: %s\n", pFormatCtx->album);
 
107
        item->setMetadata(String(MT_KEYS[M_ALBUM].upnp), 
 
108
                          sc->convert(String(pFormatCtx->album)));
 
109
        }
 
110
        if (pFormatCtx->year > 0) 
 
111
    {
 
112
            log_debug("Added metadata year: %d\n", pFormatCtx->year);
 
113
        item->setMetadata(String(MT_KEYS[M_DATE].upnp), 
 
114
                          sc->convert(String::from(pFormatCtx->year)));
 
115
        }
 
116
        if (strlen(pFormatCtx->genre) > 0) 
 
117
    {
 
118
            log_debug("Added metadata genre: %s\n", pFormatCtx->genre);
 
119
        item->setMetadata(String(MT_KEYS[M_GENRE].upnp), 
 
120
                          sc->convert(String(pFormatCtx->genre)));
 
121
        }
 
122
        if (strlen(pFormatCtx->comment) > 0) 
 
123
    {
 
124
            log_debug("Added metadata comment: %s\n", pFormatCtx->comment);
 
125
        item->setMetadata(String(MT_KEYS[M_DESCRIPTION].upnp), 
 
126
                          sc->convert(String(pFormatCtx->comment)));
 
127
        }
 
128
        if (pFormatCtx->track > 0) 
 
129
    {
 
130
            log_debug("Added metadata track: %d\n", pFormatCtx->track);
 
131
        item->setMetadata(String(MT_KEYS[M_TRACKNUMBER].upnp), 
 
132
                          sc->convert(String::from(pFormatCtx->track)));
 
133
        }
 
134
}
 
135
 
 
136
// ffmpeg library calls
 
137
static void addFfmpegResourceFields(Ref<CdsItem> item, AVFormatContext *pFormatCtx, int *x, int *y) 
 
138
{
 
139
    unsigned int i;
 
140
    int hours, mins, secs, us;
 
141
    int audioch = 0, samplefreq = 0;
 
142
    bool audioset, videoset;
 
143
    String resolution;
 
144
    char duration[15];
 
145
 
 
146
    // Initialize the buffers
 
147
    duration[0] = 0;
 
148
 
 
149
    *x = 0;
 
150
    *y = 0;
 
151
 
 
152
        // duration
 
153
    secs = pFormatCtx->duration / AV_TIME_BASE;
 
154
    us = pFormatCtx->duration % AV_TIME_BASE;
 
155
    mins = secs / 60;
 
156
    secs %= 60;
 
157
    hours = mins / 60;
 
158
    mins %= 60;
 
159
    if ((hours + mins + secs) > 0) 
 
160
    { 
 
161
        sprintf(duration, "%02d:%02d:%02d.%01d", hours, mins,
 
162
                secs, (10 * us) / AV_TIME_BASE);
 
163
        log_debug("Added duration: %s\n", duration);
 
164
        item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_DURATION), String(duration));
 
165
    }
 
166
 
 
167
        // bitrate
 
168
    if (pFormatCtx->bit_rate > 0)  
 
169
    {
 
170
        log_debug("Added overall bitrate: %d kb/s\n", 
 
171
                  pFormatCtx->bit_rate/1000);
 
172
        item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_BITRATE), String::from(pFormatCtx->bit_rate/1000));
 
173
    }
 
174
 
 
175
        // video resolution, audio sampling rate, nr of audio channels
 
176
        audioset = false;
 
177
        videoset = false;
 
178
        for(i=0; i<pFormatCtx->nb_streams; i++) 
 
179
    {
 
180
                AVStream *st = pFormatCtx->streams[i];
 
181
                if((st != NULL) && (videoset == false) && (st->codec->codec_type == CODEC_TYPE_VIDEO))
 
182
        {
 
183
            if (st->codec->codec_tag > 0)
 
184
            {
 
185
                char fourcc[5];
 
186
                fourcc[0] = st->codec->codec_tag;
 
187
                fourcc[1] = st->codec->codec_tag >> 8;
 
188
                fourcc[2] = st->codec->codec_tag >> 16;
 
189
                fourcc[3] = st->codec->codec_tag >> 24;
 
190
                fourcc[4] = '\0';
 
191
 
 
192
                log_debug("FourCC: %x = %s\n", 
 
193
                                        st->codec->codec_tag, fourcc);
 
194
                String fcc = String(fourcc);
 
195
                if (string_ok(fcc))
 
196
                    item->getResource(0)->addOption(_(RESOURCE_OPTION_FOURCC), 
 
197
                                                    fcc);
 
198
            }
 
199
 
 
200
                        if ((st->codec->width > 0) && (st->codec->height > 0)) 
 
201
            {
 
202
                resolution = String::from(st->codec->width) + "x" + 
 
203
                                    String::from(st->codec->height);
 
204
 
 
205
                                log_debug("Added resolution: %s pixel\n", resolution.c_str());
 
206
                        item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_RESOLUTION), resolution);
 
207
                                videoset = true;
 
208
                *x = st->codec->width;
 
209
                *y = st->codec->height;
 
210
                        }
 
211
                } 
 
212
                if(st->codec->codec_type == CODEC_TYPE_AUDIO) 
 
213
        {
 
214
                        // Increase number of audiochannels
 
215
                        audioch++;
 
216
                        // Get the sample rate
 
217
                        if ((audioset == false) && (st->codec->sample_rate > 0)) 
 
218
            {
 
219
                                samplefreq = st->codec->sample_rate;
 
220
                            if (samplefreq > 0) 
 
221
                {
 
222
                            log_debug("Added sample frequency: %d Hz\n", samplefreq);
 
223
                                item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_SAMPLEFREQUENCY), String::from(samplefreq));
 
224
                                        audioset = true;
 
225
                        }
 
226
                        }
 
227
                }
 
228
        }
 
229
 
 
230
    if (audioch > 0) 
 
231
    {
 
232
        log_debug("Added number of audio channels: %d\n", audioch);
 
233
        item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_NRAUDIOCHANNELS), String::from(audioch));
 
234
    }
 
235
} // addFfmpegResourceFields
 
236
 
 
237
/*double time_to_double(struct timeval time) {
 
238
        return time.tv_sec + (time.tv_usec / 1000000.0);
 
239
}*/
 
240
 
 
241
// Stub for suppressing ffmpeg error messages during matadata extraction
 
242
void FfmpegNoOutputStub(void* ptr, int level, const char* fmt, va_list vl)
 
243
{
 
244
        // do nothing
 
245
}
 
246
 
 
247
void FfmpegHandler::fillMetadata(Ref<CdsItem> item)
 
248
{
 
249
    log_debug("Running ffmpeg handler on %s\n", item->getLocation().c_str());
 
250
 
 
251
    int x = 0;
 
252
    int y = 0;
 
253
 
 
254
        AVFormatContext *pFormatCtx;
 
255
        
 
256
        // Suppress all log messages
 
257
        av_log_set_callback(FfmpegNoOutputStub);
 
258
        
 
259
        // Register all formats and codecs
 
260
    av_register_all();
 
261
 
 
262
    // Open video file
 
263
    if (av_open_input_file(&pFormatCtx, 
 
264
                          item->getLocation().c_str(), NULL, 0, NULL) != 0)
 
265
        return; // Couldn't open file
 
266
 
 
267
    // Retrieve stream information
 
268
    if (av_find_stream_info(pFormatCtx) < 0)
 
269
    {
 
270
        av_close_input_file(pFormatCtx);
 
271
        return; // Couldn't find stream information
 
272
    }   
 
273
        // Add metadata using ffmpeg library calls
 
274
        addFfmpegMetadataFields(item, pFormatCtx);
 
275
        // Add resources using ffmpeg library calls
 
276
        addFfmpegResourceFields(item, pFormatCtx, &x, &y);
 
277
        
 
278
    // Close the video file
 
279
    av_close_input_file(pFormatCtx);
 
280
}
 
281
 
 
282
Ref<IOHandler> FfmpegHandler::serveContent(Ref<CdsItem> item, int resNum, off_t *data_size)
 
283
{
 
284
    *data_size = -1;
 
285
#ifdef HAVE_FFMPEGTHUMBNAILER
 
286
    Ref<ConfigManager> cfg = ConfigManager::getInstance();
 
287
 
 
288
    if (!cfg->getBoolOption(CFG_SERVER_EXTOPTS_FFMPEGTHUMBNAILER_ENABLED))
 
289
        return nil;
 
290
 
 
291
    video_thumbnailer *th = create_thumbnailer();
 
292
    image_data *img = create_image_data();
 
293
 
 
294
    th->seek_percentage        = cfg->getIntOption(CFG_SERVER_EXTOPTS_FFMPEGTHUMBNAILER_SEEK_PERCENTAGE);
 
295
 
 
296
    if (cfg->getBoolOption(CFG_SERVER_EXTOPTS_FFMPEGTHUMBNAILER_FILMSTRIP_OVERLAY))
 
297
        th->overlay_film_strip = 1;
 
298
    else
 
299
        th->overlay_film_strip = 0;
 
300
 
 
301
    th->thumbnail_size = cfg->getIntOption(CFG_SERVER_EXTOPTS_FFMPEGTHUMBNAILER_THUMBSIZE);
 
302
    th->thumbnail_image_type   = Jpeg;
 
303
 
 
304
    log_debug("Generating thumbnail for file: %s\n", item->getLocation().c_str());
 
305
    if (generate_thumbnail_to_buffer(th, item->getLocation().c_str(), img) != 0)
 
306
        throw _Exception(_("Could not generate thumbnail for ") + item->getLocation());
 
307
 
 
308
    *data_size = (off_t)img->image_data_size;
 
309
    Ref<IOHandler> h(new MemIOHandler((void *)img->image_data_ptr, 
 
310
                                              img->image_data_size));
 
311
    destroy_image_data(img);
 
312
    destroy_thumbnailer(th);
 
313
    return h;
 
314
#else
 
315
    return nil;
 
316
#endif
 
317
}
 
318
 
 
319
String FfmpegHandler::getMimeType()
 
320
{
 
321
    Ref<ConfigManager> cfg = ConfigManager::getInstance();
 
322
 
 
323
    Ref<Dictionary> mappings = cfg->getDictionaryOption(CFG_IMPORT_MAPPINGS_MIMETYPE_TO_CONTENTTYPE_LIST);
 
324
    String thumb_mimetype = mappings->get(_(CONTENT_TYPE_JPG));
 
325
    if (!string_ok(thumb_mimetype))
 
326
        thumb_mimetype = _("image/jpeg");
 
327
    
 
328
    return thumb_mimetype;
 
329
}
 
330
#endif // HAVE_FFMPEG