~ubuntu-branches/ubuntu/breezy/kdemultimedia/breezy

« back to all changes in this revision

Viewing changes to kfile-plugins/theora/kfile_theora.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2005-03-24 04:48:58 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20050324044858-8ff88o9jxej6ii3d
Tags: 4:3.4.0-0ubuntu3
Add kubuntu_02_hide_arts_menu_entries.diff to hide artsbuilder and artscontrol k-menu entries

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2004 by Jean-Baptiste Mardelle                          *
 
3
 *   bj@altern.org                                                         *
 
4
 *                                                                         *
 
5
 *   This program is free software; you can redistribute it and/or modify  *
 
6
 *   it under the terms of the GNU General Public License as published by  *
 
7
 *   the Free Software Foundation; either version 2 of the License, or     *
 
8
 *   (at your option) any later version.                                   *
 
9
 *                                                                         *
 
10
 *   This program is distributed in the hope that it will be useful,       *
 
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
13
 *   GNU General Public License for more details.                          *
 
14
 *                                                                         *
 
15
 *   You should have received a copy of the GNU General Public License     *
 
16
 *   along with this program; if not, write to the                         *
 
17
 *   Free Software Foundation, Inc.,                                       *
 
18
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 
19
 ***************************************************************************/
 
20
 
 
21
#include <qfile.h>
 
22
#include <config.h>
 
23
#include "kfile_theora.h"
 
24
 
 
25
#include <kdebug.h>
 
26
#include <klocale.h>
 
27
#include <kgenericfactory.h>
 
28
 
 
29
#include "theora/theora.h"
 
30
#include "vorbis/codec.h"
 
31
 
 
32
ogg_stream_state t_stream_state;
 
33
ogg_stream_state v_stream_state;
 
34
 
 
35
int              theora_p=0;
 
36
int              vorbis_p=0;
 
37
 
 
38
static int queue_page(ogg_page *page)
 
39
{
 
40
    if(theora_p)
 
41
        ogg_stream_pagein(&t_stream_state,page);
 
42
    if(vorbis_p)
 
43
        ogg_stream_pagein(&v_stream_state,page);
 
44
    return 0;
 
45
}
 
46
 
 
47
static int buffer_data(FILE *in,ogg_sync_state *oy)
 
48
{
 
49
    char *buffer=ogg_sync_buffer(oy,4096);
 
50
    int bytes=fread(buffer,1,4096,in);
 
51
    ogg_sync_wrote(oy,bytes);
 
52
    return(bytes);
 
53
}
 
54
 
 
55
typedef KGenericFactory<theoraPlugin> theoraFactory;
 
56
 
 
57
K_EXPORT_COMPONENT_FACTORY(kfile_theora, theoraFactory( "kfile_theora" ))
 
58
 
 
59
theoraPlugin::theoraPlugin(QObject *parent, const char *name,
 
60
                           const QStringList &args)
 
61
        : KFilePlugin(parent, name, args)
 
62
{
 
63
//  kdDebug(7034) << "theora plugin\n";
 
64
 
 
65
    KFileMimeTypeInfo* info = addMimeTypeInfo( "video/x-theora" );
 
66
 
 
67
    KFileMimeTypeInfo::GroupInfo* group = 0;
 
68
    KFileMimeTypeInfo::ItemInfo* item;
 
69
 
 
70
    // video group
 
71
 
 
72
    group = addGroupInfo(info, "Video", i18n("Video Details"));
 
73
    setAttributes(group, 0);
 
74
    item = addItemInfo(group, "Length", i18n("Length"), QVariant::Int);
 
75
    setUnit(item, KFileMimeTypeInfo::Seconds);
 
76
    setHint(item, KFileMimeTypeInfo::Length);
 
77
    item = addItemInfo(group, "Resolution", i18n("Resolution"), QVariant::Size);
 
78
    setHint(item, KFileMimeTypeInfo::Size);
 
79
    setUnit(item, KFileMimeTypeInfo::Pixels);
 
80
    item = addItemInfo(group, "FrameRate", i18n("Frame Rate"), QVariant::Int);
 
81
    setUnit(item, KFileMimeTypeInfo::FramesPerSecond);
 
82
    item = addItemInfo(group, "TargetBitrate", i18n("Target Bitrate"), QVariant::Int);
 
83
    setUnit(item, KFileMimeTypeInfo::Bitrate);
 
84
    item = addItemInfo(group, "Quality", i18n("Quality"), QVariant::Int);
 
85
 
 
86
    // audio group
 
87
 
 
88
    group = addGroupInfo(info, "Audio", i18n("Audio Details"));
 
89
    setAttributes(group, 0);
 
90
    addItemInfo(group, "Channels", i18n("Channels"), QVariant::Int);
 
91
 
 
92
    item = addItemInfo(group, "SampleRate", i18n("Sample Rate"), QVariant::Int);
 
93
    setUnit(item, KFileMimeTypeInfo::Hertz);
 
94
}
 
95
 
 
96
bool theoraPlugin::readInfo( KFileMetaInfo& info, uint what)
 
97
{
 
98
    // most of the ogg stuff was borrowed from libtheora/examples/player_example.c
 
99
    FILE *fp;
 
100
 
 
101
    ogg_sync_state   o_sync_state;
 
102
    ogg_packet o_packet;
 
103
    ogg_page         o_page;
 
104
 
 
105
    theora_info      t_info;
 
106
    theora_comment   t_comment;
 
107
    theora_state     t_state;
 
108
    vorbis_info      v_info;
 
109
    vorbis_comment   v_comment;
 
110
 
 
111
    theora_p=0;
 
112
    vorbis_p=0;
 
113
    int theora_serial=0;
 
114
    int stateflag=0;
 
115
 
 
116
    ogg_int64_t duration=0;
 
117
 
 
118
    // libtheora is still a bit unstable and sadly the init_ functions don't
 
119
    // take care of things the way one would expect.  So, let's do some explicit
 
120
    // clearing of these fields.
 
121
 
 
122
    memset(&t_info,    0, sizeof(theora_info));
 
123
    memset(&t_comment, 0, sizeof(theora_comment));
 
124
    memset(&t_state,   0, sizeof(theora_state));
 
125
 
 
126
    bool readTech = false;
 
127
 
 
128
    if (what & (KFileMetaInfo::Fastest |
 
129
                KFileMetaInfo::DontCare |
 
130
                KFileMetaInfo::TechnicalInfo))
 
131
        readTech = true;
 
132
 
 
133
    if ( info.path().isEmpty() ) // remote file
 
134
        return false;
 
135
 
 
136
    fp = fopen(QFile::encodeName(info.path()),"rb");
 
137
    if (!fp)
 
138
    {
 
139
        kdDebug(7034) << "Unable to open " << QFile::encodeName(info.path()) << endl;
 
140
        return false;
 
141
    }
 
142
 
 
143
    ogg_sync_init(&o_sync_state);
 
144
 
 
145
    /* init supporting Vorbis structures needed in header parsing */
 
146
    vorbis_info_init(&v_info);
 
147
    vorbis_comment_init(&v_comment);
 
148
 
 
149
    /* init supporting Theora structures needed in header parsing */
 
150
    theora_comment_init(&t_comment);
 
151
    theora_info_init(&t_info);
 
152
 
 
153
    while(!stateflag && buffer_data(fp,&o_sync_state)!=0)
 
154
    {
 
155
        while (ogg_sync_pageout(&o_sync_state,&o_page)>0)
 
156
        {
 
157
            ogg_stream_state stream_test;
 
158
            /* is this a mandated initial header? If not, stop parsing */
 
159
            if(!ogg_page_bos(&o_page))
 
160
            {
 
161
                queue_page(&o_page);
 
162
                stateflag=1;
 
163
                break;
 
164
            }
 
165
 
 
166
            ogg_stream_init(&stream_test,ogg_page_serialno(&o_page));
 
167
            ogg_stream_pagein(&stream_test,&o_page);
 
168
            ogg_stream_packetout(&stream_test,&o_packet);
 
169
 
 
170
            /* identify the codec: try theora */
 
171
            if(!theora_p && theora_decode_header(&t_info,&t_comment,&o_packet)>=0)
 
172
            {
 
173
                /* it is theora */
 
174
                memcpy(&t_stream_state,&stream_test,sizeof(stream_test));
 
175
                theora_serial=ogg_page_serialno(&o_page);
 
176
                theora_p=1;
 
177
            }
 
178
            else if(!vorbis_p && vorbis_synthesis_headerin(&v_info,&v_comment,&o_packet)>=0)
 
179
            {
 
180
                /* it is vorbis */
 
181
                memcpy(&v_stream_state,&stream_test,sizeof(stream_test));
 
182
                vorbis_p=1;
 
183
            }
 
184
            else
 
185
            {
 
186
                /* whatever it is, we don't care about it */
 
187
                ogg_stream_clear(&stream_test);
 
188
            }
 
189
        }
 
190
    }
 
191
 
 
192
    /* we're expecting more header packets. */
 
193
    bool corruptedHeaders=false;
 
194
    
 
195
    while((theora_p && theora_p<3) || (vorbis_p && vorbis_p<3))
 
196
    {
 
197
        int ret;
 
198
        /* look for further theora headers */
 
199
        while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&t_stream_state,&o_packet)))
 
200
        {
 
201
            if(ret<0)
 
202
            {
 
203
                kdDebug(7034)<<"Error parsing Theora stream headers; corrupt stream?\n"<<endl;
 
204
                corruptedHeaders=true;
 
205
            }
 
206
            if(theora_decode_header(&t_info,&t_comment,&o_packet))
 
207
            {
 
208
                kdDebug(7034)<<"Error parsing Theora stream headers; corrupt stream?"<<endl;
 
209
                corruptedHeaders=true;
 
210
            }
 
211
            theora_p++;
 
212
            if(theora_p==3)
 
213
                break;
 
214
        }
 
215
 
 
216
        /* look for more vorbis header packets */
 
217
        while(vorbis_p && (vorbis_p<3) && (ret=ogg_stream_packetout(&v_stream_state,&o_packet)))
 
218
        {
 
219
            if(ret<0)
 
220
            {
 
221
                kdDebug(7034)<<"Error parsing Vorbis stream headers; corrupt stream"<<endl;
 
222
                corruptedHeaders=true;
 
223
            }
 
224
            if(vorbis_synthesis_headerin(&v_info,&v_comment,&o_packet))
 
225
            {
 
226
                kdDebug(7034)<<"Error parsing Vorbis stream headers; corrupt stream?"<<endl;
 
227
                corruptedHeaders=true;
 
228
            }
 
229
            vorbis_p++;
 
230
            if(vorbis_p==3)
 
231
                break;
 
232
        }
 
233
        /* The header pages/packets will arrive before anything else we
 
234
           care about, or the stream is not obeying spec */
 
235
 
 
236
        if(ogg_sync_pageout(&o_sync_state,&o_page)>0)
 
237
        {
 
238
            queue_page(&o_page);
 
239
            /* demux into the appropriate stream */
 
240
        }
 
241
        else
 
242
        {
 
243
            int ret=buffer_data(fp,&o_sync_state); /* someone needs more data */
 
244
            if(ret==0)
 
245
            {
 
246
                kdDebug(7034)<<"End of file while searching for codec headers."<<endl;
 
247
                corruptedHeaders=true;
 
248
            }
 
249
        }
 
250
    }
 
251
 
 
252
    /* and now we have it all.  initialize decoders */
 
253
    if(theora_p && !corruptedHeaders)
 
254
    {
 
255
        theora_decode_init(&t_state,&t_info);
 
256
    }
 
257
    else
 
258
    {
 
259
        /* tear down the partial theora setup */
 
260
        theora_info_clear(&t_info);
 
261
        theora_comment_clear(&t_comment);
 
262
 
 
263
        vorbis_info_clear(&v_info);
 
264
        vorbis_comment_clear(&v_comment);
 
265
        ogg_sync_clear(&o_sync_state);
 
266
        fclose(fp);
 
267
        return false;
 
268
    }
 
269
    //queue_page(&o_page);
 
270
 
 
271
    while (buffer_data(fp,&o_sync_state))
 
272
    {
 
273
        while (ogg_sync_pageout(&o_sync_state,&o_page)>0)
 
274
        {
 
275
            // The following line was commented out by Scott Wheeler <wheeler@kde.org>
 
276
            // We don't actually need to store all of the pages / packets in memory since
 
277
            // (a) libtheora doesn't use them anyway in the one call that we make after this
 
278
            // that usese t_state and (b) it basically buffers the entire file to memory if
 
279
            // we queue them up like this and that sucks where a typical file size is a few
 
280
            // hundred megs.
 
281
 
 
282
            // queue_page(&o_page);
 
283
        }
 
284
        if (theora_serial==ogg_page_serialno(&o_page))
 
285
            duration=(ogg_int64_t) theora_granule_time(&t_state,ogg_page_granulepos(&o_page));
 
286
    }
 
287
 
 
288
    if (readTech)
 
289
    {
 
290
        int stream_fps=0;
 
291
        if (t_info.fps_denominator!=0)
 
292
            stream_fps=t_info.fps_numerator/t_info.fps_denominator;
 
293
        KFileMetaInfoGroup videogroup = appendGroup(info, "Video");
 
294
        appendItem(videogroup, "Length", int (duration));
 
295
        appendItem(videogroup, "Resolution", QSize(t_info.frame_width,t_info.frame_height));
 
296
        appendItem(videogroup, "FrameRate", stream_fps);
 
297
        appendItem(videogroup, "Quality", (int) t_info.quality);
 
298
 
 
299
        KFileMetaInfoGroup audiogroup = appendGroup(info, "Audio");
 
300
        appendItem(audiogroup, "Channels", v_info.channels);
 
301
        appendItem(audiogroup, "SampleRate", int(v_info.rate));
 
302
    }
 
303
    fclose(fp);
 
304
 
 
305
    if (vorbis_p)
 
306
    {
 
307
        ogg_stream_clear(&v_stream_state);
 
308
        vorbis_comment_clear(&v_comment);
 
309
        vorbis_info_clear(&v_info);
 
310
    }
 
311
 
 
312
    ogg_stream_clear(&t_stream_state);
 
313
    theora_clear(&t_state);
 
314
    theora_comment_clear(&t_comment);
 
315
    theora_info_clear(&t_info);
 
316
    ogg_sync_clear(&o_sync_state);
 
317
 
 
318
    return true;
 
319
}
 
320
 
 
321
#include "kfile_theora.moc"
 
322