~ubuntu-branches/debian/experimental/gpac/experimental

« back to all changes in this revision

Viewing changes to src/media_tools/html5_mse.c

  • Committer: Package Import Robot
  • Author(s): Reinhard Tartler
  • Date: 2014-02-22 18:15:00 UTC
  • mfrom: (1.2.2) (3.1.6 sid)
  • Revision ID: package-import@ubuntu.com-20140222181500-b4phupo05gjpmopa
Tags: 0.5.0+svn5104~dfsg1-1
* New  upstream version 0.5.0+svn5104~dfsg1:
  - src/utils/sha1.c is relicensed under LGPLv2.1, Closes: #730759
* Don't install modules in multi-arch directories, Closes: #730497
* Add libusb-1.0.0-dev headers because libfreenect requires this
* Fix install rule
* Follow upstream soname bump
  - Drop the symbols file for now until it has been revised thourougly
* Let binaries produce the correct svn revision
* Refresh patches
* Patch and build against libav10, Closes: #739321
* Bump standards version, no changes necessary

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
*                       GPAC - Multimedia Framework C SDK
 
3
*
 
4
 *                      Authors: Cyril COncolato
 
5
 *                      Copyright (c) Telecom ParisTech 2013-
 
6
*                                       All rights reserved
 
7
*
 
8
*  This file is part of GPAC / Media Source
 
9
*
 
10
*  GPAC is free software; you can redistribute it and/or modify
 
11
*  it under the terms of the GNU Lesser General Public License as published by
 
12
*  the Free Software Foundation; either version 2, or (at your option)
 
13
*  any later version.
 
14
*
 
15
*  GPAC is distributed in the hope that it will be useful,
 
16
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
*  GNU Lesser General Public License for more details.
 
19
*
 
20
*  You should have received a copy of the GNU Lesser General Public
 
21
*  License along with this library; see the file COPYING.  If not, write to
 
22
*  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
23
*
 
24
*/
 
25
#include <gpac/setup.h>
 
26
 
 
27
#ifdef GPAC_HAS_SPIDERMONKEY
 
28
#include <gpac/html5_mse.h>
 
29
#include <gpac/internal/isomedia_dev.h>
 
30
 
 
31
GF_HTML_MediaSource *gf_mse_media_source_new()
 
32
{
 
33
        GF_HTML_MediaSource *ms;
 
34
        GF_SAFEALLOC(ms, GF_HTML_MediaSource);
 
35
        ms->sourceBuffers.list = gf_list_new();
 
36
        ms->sourceBuffers.parent = ms;
 
37
        ms->sourceBuffers.evt_target = gf_dom_event_target_new(GF_DOM_EVENT_TARGET_MSE_SOURCEBUFFERLIST, &ms->sourceBuffers);
 
38
        ms->activeSourceBuffers.list = gf_list_new();
 
39
        ms->activeSourceBuffers.parent = ms;
 
40
        ms->activeSourceBuffers.evt_target = gf_dom_event_target_new(GF_DOM_EVENT_TARGET_MSE_SOURCEBUFFERLIST, &ms->activeSourceBuffers);
 
41
        ms->reference_count = 1;
 
42
        ms->evt_target = gf_dom_event_target_new(GF_DOM_EVENT_TARGET_MSE_MEDIASOURCE, ms);
 
43
        return ms;
 
44
}
 
45
 
 
46
GF_EXPORT
 
47
void gf_mse_mediasource_del(GF_HTML_MediaSource *ms, Bool del_js) 
 
48
{
 
49
        if (ms) {
 
50
                if (del_js) {
 
51
                        /* finalize the object from the JS perspective */
 
52
                        ms->c = NULL;
 
53
                        ms->_this = NULL;
 
54
                }
 
55
                /* only delete the object if it is not used elsewhere */
 
56
                if (ms->reference_count) {
 
57
                        ms->reference_count--;
 
58
                }
 
59
                if (!ms->reference_count) {
 
60
                        u32 i;
 
61
                        for (i = 0; i < gf_list_count(ms->sourceBuffers.list); i++) {
 
62
                                GF_HTML_SourceBuffer *sb = (GF_HTML_SourceBuffer *)gf_list_get(ms->sourceBuffers.list, i);
 
63
 
 
64
                                if (sb->parser && sb->parser_connected)
 
65
                                        sb->parser->CloseService(sb->parser);
 
66
 
 
67
                                gf_mse_source_buffer_del(sb);
 
68
                        }
 
69
                        gf_list_del(ms->sourceBuffers.list);
 
70
                        /* all source buffer should have been deleted in the deletion of sourceBuffers */
 
71
                        gf_list_del(ms->activeSourceBuffers.list); 
 
72
                        if (ms->blobURI) gf_free(ms->blobURI);
 
73
                        gf_free(ms->evt_target);
 
74
                        gf_free(ms);
 
75
                }
 
76
        }
 
77
}
 
78
 
 
79
static void gf_mse_fire_event(GF_DOMEventTarget *target, GF_EventType event_type) 
 
80
{
 
81
        GF_SceneGraph *sg = NULL;
 
82
    GF_DOM_Event  mse_event;
 
83
        memset(&mse_event, 0, sizeof(GF_DOM_Event));
 
84
    mse_event.type = event_type;
 
85
        mse_event.target = target->ptr;
 
86
        mse_event.target_type = target->ptr_type;
 
87
        switch(target->ptr_type) {
 
88
        case GF_DOM_EVENT_TARGET_MSE_MEDIASOURCE:
 
89
                {
 
90
                        GF_HTML_MediaSource *ms = (GF_HTML_MediaSource *)target->ptr;
 
91
                        sg = ms->sg;
 
92
                }
 
93
                break;
 
94
        case GF_DOM_EVENT_TARGET_MSE_SOURCEBUFFERLIST:
 
95
                {
 
96
                        GF_HTML_SourceBufferList *list = (GF_HTML_SourceBufferList *)target->ptr;
 
97
                        sg = list->parent->sg;
 
98
                }
 
99
                break;
 
100
        case GF_DOM_EVENT_TARGET_MSE_SOURCEBUFFER:
 
101
                {
 
102
                        GF_HTML_SourceBuffer *sb = (GF_HTML_SourceBuffer *)target->ptr;
 
103
                        sg = sb->mediasource->sg;
 
104
                }
 
105
                break;
 
106
        default:
 
107
                break;
 
108
        }
 
109
        assert(sg);
 
110
    sg_fire_dom_event(target, &mse_event, sg, NULL);
 
111
}
 
112
 
 
113
GF_EXPORT
 
114
void gf_mse_mediasource_open(GF_HTML_MediaSource *ms, struct _mediaobj *mo) 
 
115
{
 
116
        if (!ms) return;
 
117
        if (!mo) {
 
118
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[MSE] Cannot open media source without a media object\n"));
 
119
                return;
 
120
        }
 
121
    ms->readyState = MEDIA_SOURCE_READYSTATE_OPEN;
 
122
        /* getting the Scene Tree node attached to this media source */
 
123
        ms->node = (GF_Node *)gf_event_target_get_node(gf_mo_event_target_get(mo, 0));
 
124
        ms->sg = gf_node_get_graph(ms->node);
 
125
        gf_mse_fire_event(ms->evt_target, GF_EVENT_HTML_MSE_SOURCE_OPEN);
 
126
}
 
127
 
 
128
GF_EXPORT
 
129
void gf_mse_mediasource_close(GF_HTML_MediaSource *ms)
 
130
{
 
131
        if (!ms) return;
 
132
    ms->readyState = MEDIA_SOURCE_READYSTATE_CLOSED;
 
133
        gf_mse_fire_event(ms->evt_target, GF_EVENT_HTML_MSE_SOURCE_CLOSE);
 
134
}
 
135
 
 
136
GF_EXPORT
 
137
void gf_mse_mediasource_end(GF_HTML_MediaSource *ms)
 
138
{
 
139
        if (!ms) return;
 
140
    ms->readyState = MEDIA_SOURCE_READYSTATE_ENDED;
 
141
        gf_mse_fire_event(ms->evt_target, GF_EVENT_HTML_MSE_SOURCE_ENDED);
 
142
}
 
143
 
 
144
GF_HTML_SourceBuffer *gf_mse_source_buffer_new(GF_HTML_MediaSource *mediasource)
 
145
{
 
146
    char name[256];
 
147
    GF_HTML_SourceBuffer *source;
 
148
    GF_SAFEALLOC(source, GF_HTML_SourceBuffer);
 
149
    sprintf(name, "SourceBuffer_Thread_%p", source);
 
150
    source->mediasource = mediasource;
 
151
    source->buffered.times = gf_list_new();
 
152
    source->input_buffer = gf_list_new();
 
153
    source->tracks = gf_list_new();
 
154
    source->parser_thread = gf_th_new(name);
 
155
    source->remove_thread = gf_th_new(name);
 
156
    source->append_mode = MEDIA_SOURCE_APPEND_MODE_SEGMENTS;
 
157
    source->appendWindowStart = 0;
 
158
    source->appendWindowEnd = GF_MAX_DOUBLE;
 
159
        source->evt_target = gf_dom_event_target_new(GF_DOM_EVENT_TARGET_MSE_SOURCEBUFFER, source);
 
160
    return source;
 
161
}
 
162
 
 
163
void gf_mse_add_source_buffer(GF_HTML_MediaSource *ms, GF_HTML_SourceBuffer *sb) 
 
164
{
 
165
    gf_list_add(ms->sourceBuffers.list, sb);
 
166
        gf_mse_fire_event(ms->sourceBuffers.evt_target, GF_EVENT_HTML_MSE_ADD_SOURCE_BUFFER);
 
167
}
 
168
 
 
169
static void gf_mse_reset_input_buffer(GF_List *input_buffer)
 
170
{
 
171
        while (gf_list_count(input_buffer)) {
 
172
                GF_HTML_ArrayBuffer *b = (GF_HTML_ArrayBuffer *)gf_list_get(input_buffer, 0);
 
173
                gf_list_rem(input_buffer, 0);
 
174
                gf_arraybuffer_del(b, GF_FALSE);
 
175
        }
 
176
}
 
177
 
 
178
void gf_mse_source_buffer_del(GF_HTML_SourceBuffer *sb)
 
179
{
 
180
    GF_HTML_TrackList tlist;
 
181
    gf_html_timeranges_del(&sb->buffered);
 
182
    gf_mse_reset_input_buffer(sb->input_buffer);
 
183
    gf_list_del(sb->input_buffer);
 
184
 
 
185
        if (sb->prev_buffer) gf_arraybuffer_del((GF_HTML_ArrayBuffer *)sb->prev_buffer, GF_FALSE);
 
186
 
 
187
        tlist.tracks = sb->tracks;
 
188
    gf_html_tracklist_del(&tlist);
 
189
    gf_th_del(sb->parser_thread);
 
190
    gf_th_del(sb->remove_thread);
 
191
 
 
192
        if (sb->service_desc) gf_odf_desc_del((GF_Descriptor *)sb->service_desc);
 
193
    gf_free(sb);
 
194
 
 
195
}
 
196
 
 
197
void gf_mse_source_buffer_set_update(GF_HTML_SourceBuffer *sb, Bool update)
 
198
{
 
199
        if (sb->updating == update) return;
 
200
        sb->updating = update;
 
201
        if (update) {
 
202
                gf_mse_fire_event(sb->evt_target, GF_EVENT_HTML_MSE_UPDATE_START);
 
203
        } else {
 
204
                gf_mse_fire_event(sb->evt_target, GF_EVENT_HTML_MSE_UPDATE);
 
205
                gf_mse_fire_event(sb->evt_target, GF_EVENT_HTML_MSE_UPDATE_END);
 
206
        }
 
207
}
 
208
 
 
209
/*locates and loads an input service (demuxer, parser) for this source buffer based on mime type or segment name*/
 
210
GF_Err gf_mse_source_buffer_load_parser(GF_HTML_SourceBuffer *sourcebuffer, const char *mime)
 
211
{
 
212
    GF_InputService *parser = NULL;
 
213
 
 
214
    const char *sPlug;
 
215
    if (mime) {
 
216
                /* strip the 'codecs' and 'profile' parameters from the MIME type */
 
217
                char *param = (char *)strchr(mime, ';');
 
218
                if (param) {
 
219
                        *param = 0;
 
220
                }
 
221
 
 
222
        /* Check MIME type to start the right InputService */
 
223
        sPlug = gf_cfg_get_key(sourcebuffer->mediasource->service->term->user->config, "MimeTypes", mime);
 
224
        if (sPlug) sPlug = strrchr(sPlug, '"');
 
225
        if (sPlug) {
 
226
            sPlug += 2;
 
227
            parser = (GF_InputService *) gf_modules_load_interface_by_name(sourcebuffer->mediasource->service->term->user->modules, sPlug, GF_NET_CLIENT_INTERFACE);
 
228
        }
 
229
 
 
230
                if (param) {
 
231
                        *param = ';';
 
232
                }
 
233
    }
 
234
    if (parser) {
 
235
        sourcebuffer->parser = parser;
 
236
        parser->query_proxy = gf_mse_proxy;
 
237
        parser->proxy_udta = sourcebuffer;
 
238
        parser->proxy_type = GF_TRUE;
 
239
        return GF_OK;
 
240
    } else {
 
241
        GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[MSE] Error locating plugin for source - mime type %s\n", mime));
 
242
        return GF_BAD_PARAM;
 
243
    }
 
244
}
 
245
 
 
246
/* create a track based on the ESD and adds it to the source buffer */
 
247
static GF_HTML_Track *gf_mse_source_buffer_add_track(GF_HTML_SourceBuffer *sb, GF_ESD *esd)
 
248
{
 
249
    GF_HTML_Track *track;
 
250
    GF_HTML_TrackType type;
 
251
 
 
252
    track = NULL;
 
253
    type = HTML_MEDIA_TRACK_TYPE_UNKNOWN;
 
254
    if (esd->decoderConfig->streamType==GF_STREAM_VISUAL) {
 
255
        type = HTML_MEDIA_TRACK_TYPE_VIDEO;
 
256
    } else if (esd->decoderConfig->streamType==GF_STREAM_AUDIO) {
 
257
        type = HTML_MEDIA_TRACK_TYPE_AUDIO;
 
258
    } else {
 
259
        /* TODO: Text tracks */
 
260
    }
 
261
 
 
262
    track = gf_html_media_track_new(type, "", GF_TRUE, "", "", "", "");
 
263
    if (track) {
 
264
        char mx_name[256];
 
265
        track->bin_id = esd->ESID;
 
266
        track->buffer = gf_list_new();
 
267
        sprintf(mx_name, "track_mutex_%d", track->bin_id);
 
268
        track->buffer_mutex = gf_mx_new(mx_name);
 
269
        track->timescale = esd->slConfig->timestampResolution;
 
270
        gf_list_add(sb->tracks, track);
 
271
    }
 
272
    return track;
 
273
}
 
274
 
 
275
/* Creates the different tracks based on the demuxer parser information 
 
276
   Needs the parser to be setup and the initialization segment passed */
 
277
static GF_Err gf_mse_source_buffer_setup_tracks(GF_HTML_SourceBuffer *sb)
 
278
{
 
279
        if (!sb || !sb->parser || !sb->parser_connected) return GF_BAD_PARAM;
 
280
    sb->service_desc = (GF_ObjectDescriptor *)sb->parser->GetServiceDescriptor(sb->parser, GF_MEDIA_OBJECT_UNDEF, NULL);
 
281
    if (sb->service_desc) {
 
282
        u32 count;
 
283
        count = gf_list_count(sb->service_desc->ESDescriptors);
 
284
        if (count) {
 
285
            u32 i;
 
286
            for (i = 0; i < count; i++) {
 
287
                GF_ESD *esd = (GF_ESD *)gf_list_get(sb->service_desc->ESDescriptors, i);
 
288
                gf_mse_source_buffer_add_track(sb, esd);
 
289
            }
 
290
        }
 
291
        return GF_OK;
 
292
    } else {
 
293
        return GF_BAD_PARAM;
 
294
    }
 
295
}
 
296
 
 
297
/* Adds the ObjectDescriptor to the associated track (creating a new track if needed)
 
298
   Called in response to addmedia events received from the parser */
 
299
static GF_Err gf_mse_source_buffer_store_track_desc(GF_HTML_SourceBuffer *sb, GF_ObjectDescriptor *od)
 
300
{
 
301
    u32 i;
 
302
    u32 count;
 
303
    GF_ESD *esd;
 
304
    Bool found = GF_FALSE;
 
305
    GF_HTML_Track *track;
 
306
 
 
307
    esd = (GF_ESD *)gf_list_get(od->ESDescriptors, 0);
 
308
    count = gf_list_count(sb->tracks);
 
309
    for (i = 0; i < count; i++) {
 
310
        track = (GF_HTML_Track *)gf_list_get(sb->tracks, i);
 
311
        if (track->bin_id == esd->ESID) {
 
312
            track->od = od;
 
313
            found = GF_TRUE;
 
314
            break;
 
315
        }
 
316
    }
 
317
    if (!found) {
 
318
        track = gf_mse_source_buffer_add_track(sb, esd);
 
319
        if (track) {
 
320
            track->od = od;
 
321
        } else {
 
322
            /* TODO: error */
 
323
            return GF_BAD_PARAM;
 
324
        }
 
325
    } 
 
326
    return GF_OK;
 
327
}
 
328
 
 
329
/* Traverses the list of Access Units already demuxed & parsed to update the buffered status */
 
330
void gf_mse_source_buffer_update_buffered(GF_HTML_SourceBuffer *sb) {
 
331
    u32 i;
 
332
    u32 track_count;
 
333
    double start= 0;
 
334
    double end = 0;
 
335
    Bool start_set = GF_FALSE;
 
336
    Bool end_set = GF_FALSE;
 
337
        u64 au_dur = 0;
 
338
        double packet_start;
 
339
        double packet_end;
 
340
 
 
341
    /* cleaning the current list */
 
342
    gf_html_timeranges_reset(&(sb->buffered));
 
343
 
 
344
    /* merging the start and end for all tracks */
 
345
    track_count = gf_list_count(sb->tracks);
 
346
    for (i = 0; i < track_count; i++) {
 
347
        u32 j;
 
348
        u32 packet_count;
 
349
        GF_HTML_Track *track = (GF_HTML_Track *)gf_list_get(sb->tracks, i);
 
350
        gf_mx_p(track->buffer_mutex);
 
351
        packet_count = gf_list_count(track->buffer);
 
352
                au_dur = 0;
 
353
        for (j = 0; j < packet_count; j++) {
 
354
            GF_MSE_Packet *packet = (GF_MSE_Packet *)gf_list_get(track->buffer, j);
 
355
            if (packet) {
 
356
                packet_start = (packet->sl_header.compositionTimeStamp * 1.0 )/ track->timescale;
 
357
                                if (packet->sl_header.au_duration) {
 
358
                                        au_dur = packet->sl_header.au_duration;
 
359
                                } else {
 
360
                                        if (j > 0) {
 
361
                                                GF_MSE_Packet *prev = (GF_MSE_Packet *)gf_list_get(track->buffer, j-1);
 
362
                                                au_dur = packet->sl_header.decodingTimeStamp - prev->sl_header.decodingTimeStamp;
 
363
                                        }
 
364
                                }
 
365
                packet_end = ((packet->sl_header.compositionTimeStamp + au_dur) * 1.0) / track->timescale;
 
366
                if (!start_set) {
 
367
                    start = packet_start;
 
368
                    start_set = GF_TRUE;
 
369
                } else {
 
370
                    if (start > packet_start) {
 
371
                        start = packet_start;
 
372
                    }
 
373
                }
 
374
                                if (!end_set) {
 
375
                    end = packet_end;
 
376
                    end_set = GF_TRUE;
 
377
                } else {
 
378
                    if (end < packet_end) {
 
379
                        end = packet_end;
 
380
                    }
 
381
                }
 
382
            }
 
383
        }
 
384
        gf_mx_v(track->buffer_mutex);
 
385
    }
 
386
 
 
387
    /* Creating only one range for now */
 
388
    if (start_set && end_set) {
 
389
        gf_media_time_ranges_add(&sb->buffered, start, end);
 
390
    } 
 
391
}
 
392
 
 
393
/* Deletes all unparsed data buffers from all tracks in the source buffer */
 
394
static void gf_mse_source_buffer_reset_parser(GF_HTML_SourceBuffer *sb)
 
395
{
 
396
    u32 i, track_count;
 
397
    track_count = gf_list_count(sb->tracks);
 
398
 
 
399
    /* wait until all remaining entire AU are parsed and then flush the remaining bytes in the parser */
 
400
 
 
401
    for (i = 0; i < track_count; i++) 
 
402
    {
 
403
        GF_HTML_Track *track = (GF_HTML_Track *)gf_list_get(sb->tracks, i);
 
404
        track->last_dts_set     = GF_FALSE;
 
405
        track->highest_pts_set  = GF_FALSE;
 
406
        track->needs_rap        = GF_TRUE;
 
407
    }
 
408
    sb->highest_end_timestamp_set = GF_FALSE;
 
409
    gf_mse_reset_input_buffer(sb->input_buffer);
 
410
    sb->append_state = MEDIA_SOURCE_APPEND_STATE_WAITING_FOR_SEGMENT;
 
411
}
 
412
 
 
413
GF_Err gf_mse_source_buffer_abort(GF_HTML_SourceBuffer *sb)
 
414
{
 
415
/*
 
416
if (sb->continuation_timestamp_flag == GF_FALSE)
 
417
    {
 
418
        if (sb->abort_mode == MEDIA_SOURCE_ABORT_MODE_CONTINUATION && !sb->highest_end_timestamp_set)
 
419
        {
 
420
            return GF_BAD_PARAM;
 
421
        }
 
422
 
 
423
        if (sb->highest_end_timestamp_set) {
 
424
            sb->continuation_timestamp = sb->highest_end_timestamp;
 
425
            sb->continuation_timestamp_flag = GF_TRUE;
 
426
        }
 
427
    }
 
428
//    sb->abort_mode = mode;
 
429
*/
 
430
        gf_mse_source_buffer_set_update(sb, GF_FALSE);
 
431
    sb->appendWindowStart = 0;
 
432
    sb->appendWindowEnd = GF_MAX_DOUBLE;
 
433
        /*fire abort event at the SourceBuffer */       
 
434
    gf_mse_source_buffer_reset_parser(sb);
 
435
    return GF_OK;
 
436
}
 
437
 
 
438
void gf_mse_packet_del(GF_MSE_Packet *packet) {
 
439
    gf_free(packet->data);
 
440
    gf_free(packet);
 
441
}
 
442
 
 
443
static GF_MSE_Packet *gf_mse_find_overlapped_packet(GF_HTML_Track           *track, 
 
444
                                                    GF_MSE_Packet           *packet)
 
445
{
 
446
    u32     i;
 
447
    u32     count;
 
448
    Bool    found_previous;
 
449
    
 
450
    found_previous = GF_FALSE;
 
451
    gf_mx_p(track->buffer_mutex);
 
452
    count = gf_list_count(track->buffer);
 
453
    for (i = 0; i < count; i++)
 
454
    {
 
455
        GF_MSE_Packet *p = (GF_MSE_Packet *)gf_list_get(track->buffer, i);
 
456
        if (p->sl_header.compositionTimeStamp < packet->sl_header.compositionTimeStamp) {
 
457
            found_previous = GF_TRUE;
 
458
        }
 
459
        if (found_previous == GF_TRUE && p->sl_header.compositionTimeStamp > packet->sl_header.compositionTimeStamp) {
 
460
            return p;
 
461
        }
 
462
    }
 
463
    gf_mx_v(track->buffer_mutex);
 
464
    return NULL;
 
465
}
 
466
 
 
467
static void gf_mse_remove_frames_from_to(GF_HTML_Track *track, 
 
468
                                         u64           from,
 
469
                                         u64           to)
 
470
{
 
471
    u32     i;
 
472
    u32     frame_count;
 
473
 
 
474
    gf_mx_p(track->buffer_mutex);
 
475
    frame_count = gf_list_count(track->buffer);
 
476
    for (i = 0; i < frame_count; i++) {
 
477
        GF_MSE_Packet *frame = (GF_MSE_Packet *)gf_list_get(track->buffer, i);
 
478
        if (frame->sl_header.compositionTimeStamp >= from && frame->sl_header.compositionTimeStamp < to) {
 
479
            GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Removing frame %g (%d frames)\n", (frame->sl_header.compositionTimeStamp*1.0)/track->timescale, gf_list_count(track->buffer)));
 
480
            gf_list_rem(track->buffer, i);
 
481
        }
 
482
    }
 
483
    gf_mx_v(track->buffer_mutex);
 
484
}
 
485
 
 
486
static GF_Err gf_mse_process_coded_frame(GF_HTML_SourceBuffer    *sb, 
 
487
                                       GF_HTML_Track           *track, 
 
488
                                       GF_MSE_Packet           *frame,
 
489
                                                                           Bool *stored)
 
490
{
 
491
        *stored = GF_FALSE;
 
492
    if (sb->append_mode == MEDIA_SOURCE_APPEND_MODE_SEQUENCE && sb->group_start_timestamp_flag) {
 
493
        sb->timestampOffset = sb->group_start_timestamp - (frame->sl_header.compositionTimeStamp*1.0/track->timescale);
 
494
                sb->highest_end_timestamp = sb->group_start_timestamp;
 
495
                track->needs_rap = GF_TRUE; /* fix: should be on all track buffers */
 
496
                sb->group_start_timestamp_flag = GF_FALSE;
 
497
    }
 
498
 
 
499
    if (sb->timestampOffset != 0) {
 
500
        u64 offset = (u64)((sb->timestampOffset)*track->timescale);
 
501
        if (offset > frame->sl_header.compositionTimeStamp || offset > frame->sl_header.decodingTimeStamp) {
 
502
             return GF_NON_COMPLIANT_BITSTREAM;
 
503
        }
 
504
                frame->sl_header.compositionTimeStamp  += (u64)(sb->timestampOffset*track->timescale);
 
505
                frame->sl_header.decodingTimeStamp     += (u64)(sb->timestampOffset*track->timescale);
 
506
                /* check if the new CTS/DTS are in range */
 
507
    }
 
508
 
 
509
    if (track->last_dts_set) {
 
510
        if (track->last_dts*track->timescale > frame->sl_header.decodingTimeStamp) {
 
511
            return GF_NON_COMPLIANT_BITSTREAM;
 
512
        }
 
513
 
 
514
        /* why ??? 
 
515
         * If last decode timestamp for track buffer is set and decode timestamp is less than last decode timestamp 
 
516
         * or the difference between decode timestamp and last decode timestamp is greater than 100 milliseconds, 
 
517
         * then call endOfStream("decode") and abort these steps.
 
518
         */
 
519
        if (frame->sl_header.decodingTimeStamp - track->last_dts*track->timescale > 0.1*track->timescale) {
 
520
            return GF_NON_COMPLIANT_BITSTREAM;
 
521
        }
 
522
    }
 
523
 
 
524
    if (frame->sl_header.compositionTimeStamp < sb->appendWindowStart*track->timescale) {
 
525
        track->needs_rap = GF_TRUE;
 
526
        return GF_OK;
 
527
    }
 
528
 
 
529
    if (frame->sl_header.compositionTimeStamp /* + dur */ > sb->appendWindowEnd*track->timescale) {
 
530
        track->needs_rap = GF_TRUE;
 
531
        return GF_OK;
 
532
    }
 
533
 
 
534
    if (track->needs_rap) {
 
535
        if (!frame->sl_header.randomAccessPointFlag) {
 
536
            return GF_OK;
 
537
        }
 
538
        track->needs_rap = GF_FALSE;
 
539
    }
 
540
 
 
541
    if (!track->last_dts_set) {
 
542
        /* find a frame in the track buffer whose PTS is less than the current packet and whose PTS + dur is greater than the current packet */
 
543
        GF_MSE_Packet           *overlapped_packet;
 
544
        overlapped_packet = gf_mse_find_overlapped_packet(track, frame);
 
545
        if (overlapped_packet) {
 
546
            gf_mse_remove_frames_from_to(track, overlapped_packet->sl_header.compositionTimeStamp, overlapped_packet->sl_header.compositionTimeStamp + (u64)(0.000001*track->timescale));
 
547
        }
 
548
    } 
 
549
 
 
550
    if (!track->highest_pts_set) {
 
551
        /* this is the first time a frame is processed in the append sequence */
 
552
        gf_mse_remove_frames_from_to(track, frame->sl_header.compositionTimeStamp, frame->sl_header.compositionTimeStamp /* + dur */);
 
553
    } else if (track->highest_pts*track->timescale <= frame->sl_header.compositionTimeStamp) {
 
554
        /* the highest pts has already been set in this append sequence, so we just need to remove frames from that point on, it's safe */
 
555
        gf_mse_remove_frames_from_to(track, (u64)(track->highest_pts*track->timescale), (u64)(track->highest_pts*track->timescale) /* + dur */);
 
556
    }
 
557
 
 
558
    /* remove dependencies: no way !! */
 
559
 
 
560
    /* TODO: spliced frames */
 
561
 
 
562
        *stored = GF_TRUE;
 
563
    gf_mx_p(track->buffer_mutex);
 
564
    gf_list_add(track->buffer, frame);
 
565
    GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Adding frame %g (%d frames)\n", (frame->sl_header.compositionTimeStamp*1.0)/track->timescale, gf_list_count(track->buffer)));
 
566
    gf_mx_v(track->buffer_mutex);
 
567
 
 
568
    track->last_dts = (frame->sl_header.decodingTimeStamp*1.0/track->timescale);
 
569
    track->last_dts_set = GF_TRUE;
 
570
 
 
571
    if (!track->highest_pts_set || (frame->sl_header.compositionTimeStamp /* + dur */) > track->highest_pts*track->timescale) {
 
572
        track->highest_pts_set = GF_TRUE;
 
573
        track->highest_pts = (frame->sl_header.compositionTimeStamp*1.0/track->timescale /* + dur */);
 
574
    }
 
575
 
 
576
    if (!sb->highest_end_timestamp_set || (frame->sl_header.compositionTimeStamp*1.0 /* + dur */) > sb->highest_end_timestamp * track->timescale) {
 
577
        sb->highest_end_timestamp_set = GF_TRUE;
 
578
        sb->highest_end_timestamp = (frame->sl_header.compositionTimeStamp*1.0/track->timescale /* + dur */);
 
579
    }
 
580
 
 
581
    return GF_OK;
 
582
}
 
583
 
 
584
/* Thread run function: called as a result of an append buffer 
 
585
 * Parses/Demultiplexes media segments and places the parsed AU in the track buffers 
 
586
 *
 
587
 * \param par the GF_HTML_SourceBuffer object used for the append
 
588
 */
 
589
u32 gf_mse_parse_segment(void *par)
 
590
{
 
591
    GF_MSE_Packet           *packet;
 
592
    GF_HTML_Track           *track;
 
593
    GF_HTML_SourceBuffer    *sb = (GF_HTML_SourceBuffer *)par;
 
594
    u32                     i;
 
595
    u32                     track_count;
 
596
 
 
597
    if (!sb->parser_connected) {
 
598
                GF_HTML_ArrayBuffer *buffer = (GF_HTML_ArrayBuffer *)gf_list_get(sb->input_buffer, 0);
 
599
                gf_list_rem(sb->input_buffer, 0);                  
 
600
                assert(buffer);
 
601
                /* we expect an initialization segment to connect the service */
 
602
                if (!buffer->is_init) {
 
603
                        /* TODO: set the media element decode error and run the end of stream algo */
 
604
                        goto exit;
 
605
                }
 
606
        sb->parser->ConnectService(sb->parser, sb->mediasource->service, buffer->url);
 
607
                sb->prev_buffer = buffer;
 
608
    } else {
 
609
        /* we expect a media segment */
 
610
                GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Starting to fetch AUs from parser\n"));
 
611
 
 
612
                /* For each track, ask the parser for all the Access Unit, until it is empty
 
613
                 * AU are placed as GF_MSE_Packets in the track buffer 
 
614
                 */
 
615
                track_count = gf_list_count(sb->tracks);
 
616
                while (1) {
 
617
                        u32 track_with_data = 0;
 
618
                        for (i = 0; i < track_count; i++) {
 
619
                                Bool stored = GF_FALSE;
 
620
                                GF_Err e;
 
621
                                track = (GF_HTML_Track *)gf_list_get(sb->tracks, i);
 
622
                                GF_SAFEALLOC(packet, GF_MSE_Packet);
 
623
                                assert(track->channel);
 
624
                                e = sb->parser->ChannelGetSLP(sb->parser, track->channel, 
 
625
                                                                                          &packet->data, &packet->size, &packet->sl_header, 
 
626
                                                                                          &packet->is_compressed, &packet->status, &packet->is_new_data);
 
627
                                assert(e == GF_OK);
 
628
                                if (packet->status == GF_OK && packet->is_new_data && packet->size) {
 
629
                                        char *data;
 
630
                                        assert(packet->is_new_data && packet->size);
 
631
                                        data = (char *)gf_malloc(packet->size);
 
632
                                        GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] New AU parsed %g\n", (packet->sl_header.compositionTimeStamp*1.0/track->timescale)));
 
633
                                        memcpy(data, packet->data, packet->size);
 
634
                                        packet->data = data;
 
635
                                        gf_mse_process_coded_frame(sb, track, packet, &stored);
 
636
                                        track_with_data++;
 
637
                                        sb->parser->ChannelReleaseSLP(sb->parser, track->channel);
 
638
                                }
 
639
 
 
640
                                if (!stored) gf_free(packet);
 
641
                        }
 
642
                        if (!track_with_data) {
 
643
                                /* try to delete the previous buffer */
 
644
                                gf_arraybuffer_del((GF_HTML_ArrayBuffer *)sb->prev_buffer, GF_FALSE);
 
645
                                sb->prev_buffer = NULL;
 
646
                                /* get ready to receive a new segment and start a new thread */
 
647
                                break;
 
648
                        }
 
649
                }
 
650
                /* reaching here, the parser does not have enough data to produce new AU */
 
651
                GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Done fetching AUs from parser\n"));
 
652
    }
 
653
exit:
 
654
        gf_mse_source_buffer_set_update(sb, GF_FALSE);
 
655
    return 0;
 
656
}
 
657
 
 
658
 
 
659
void gf_mse_source_buffer_append_arraybuffer(GF_HTML_SourceBuffer *sb, GF_HTML_ArrayBuffer *buffer)
 
660
{
 
661
        assert(sb->parser);
 
662
        gf_mse_source_buffer_set_update(sb, GF_TRUE);
 
663
 
 
664
    buffer->url = (char *)gf_malloc(256);
 
665
    sprintf(buffer->url, "gmem://%d@%p", buffer->length, buffer->data);
 
666
    buffer->reference_count++;
 
667
        buffer->is_init = (gf_isom_probe_file(buffer->url) == 2 ? GF_TRUE : GF_FALSE);
 
668
    GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Appending segment %s to SourceBuffer %p\n", buffer->url, sb));
 
669
 
 
670
    gf_list_add(sb->input_buffer, buffer);
 
671
    /* Call the parser (asynchronously) and return */
 
672
    /* the updating attribute will be positioned back to 0 when the parser is done */
 
673
    gf_th_run(sb->parser_thread, gf_mse_parse_segment, sb);
 
674
}
 
675
 
 
676
/*
 
677
FIXME : Unused function, create warnings on debian
 
678
static void gf_mse_source_buffer_append_error(GF_HTML_SourceBuffer *sb)
 
679
{
 
680
    sb->updating = GF_FALSE;
 
681
    gf_mse_source_buffer_reset_parser(sb);
 
682
    TODO: fire events
 
683
}
 
684
*/
 
685
 
 
686
/* Threaded function called upon request from JS
 
687
   - Removes data in each track buffer until the next RAP is found */
 
688
u32 gf_mse_source_buffer_remove(void *par)
 
689
{
 
690
    GF_HTML_SourceBuffer    *sb = (GF_HTML_SourceBuffer *)par;
 
691
    u32                     i;
 
692
    u32                     j;
 
693
    u32                     track_count;
 
694
    u32                     frame_count;
 
695
    u64                     end = 0;
 
696
    //Bool                    end_set;
 
697
 
 
698
    GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Removing media until next RAP\n"));
 
699
 
 
700
    track_count = gf_list_count(sb->tracks);
 
701
    for (i = 0; i < track_count; i++) {
 
702
        GF_HTML_Track *track = (GF_HTML_Track *)gf_list_get(sb->tracks, i);
 
703
        //end_set = GF_FALSE;
 
704
 
 
705
        /* find the next random access point */
 
706
        gf_mx_p(track->buffer_mutex);
 
707
        frame_count = gf_list_count(track->buffer);
 
708
        for (j = 0; j < frame_count; j++) {
 
709
            GF_MSE_Packet *frame = (GF_MSE_Packet *)gf_list_get(track->buffer, j);
 
710
            if ((frame->sl_header.randomAccessPointFlag && 
 
711
                 frame->sl_header.compositionTimeStamp >= sb->remove_end*track->timescale) ||
 
712
                 (j == frame_count - 1)) {
 
713
                end = frame->sl_header.compositionTimeStamp;
 
714
                //end_set = GF_TRUE;
 
715
                break;
 
716
            }
 
717
        }
 
718
        gf_mx_v(track->buffer_mutex);
 
719
 
 
720
        /* remove up to the next RAP found */
 
721
        gf_mse_remove_frames_from_to(track, (u64)sb->remove_start, end);
 
722
    }
 
723
        gf_mse_source_buffer_set_update(sb, GF_FALSE);
 
724
    return 0;
 
725
}
 
726
 
 
727
/* Callback functions used by a media parser when parsing events happens */
 
728
GF_Err gf_mse_proxy(GF_InputService *parser, GF_NetworkCommand *command)
 
729
{
 
730
    if (!parser || !command || !parser->proxy_udta) {
 
731
        return GF_BAD_PARAM;
 
732
    } else {
 
733
        GF_HTML_SourceBuffer *sb = (GF_HTML_SourceBuffer *)parser->proxy_udta;
 
734
        switch (command->command_type) {
 
735
        case GF_NET_SERVICE_QUERY_INIT_RANGE:
 
736
                        break;
 
737
        case GF_NET_SERVICE_QUERY_NEXT:
 
738
            /* The parser is asking for the next media segment in the buffer,
 
739
               check for the media time and give the right one */
 
740
            {
 
741
                GF_HTML_ArrayBuffer *buffer;
 
742
                /* The input buffer should not be modified by append operations at the same time, no need to protect access */
 
743
                buffer = (GF_HTML_ArrayBuffer *)gf_list_get(sb->input_buffer, 0);
 
744
                if (buffer) {
 
745
                                        command->url_query.discontinuity_type = 0;
 
746
                                        command->url_query.current_download = GF_FALSE;
 
747
                                        command->url_query.start_range = 0;
 
748
                                        command->url_query.end_range = 0;
 
749
                                        command->url_query.switch_start_range = 0;
 
750
                                        command->url_query.switch_end_range = 0;
 
751
                                        command->url_query.next_url_init_or_switch_segment = NULL;
 
752
                                        if (buffer->is_init) { 
 
753
                                                GF_HTML_ArrayBuffer *next = (GF_HTML_ArrayBuffer *)gf_list_get(sb->input_buffer, 1);
 
754
                                                command->url_query.discontinuity_type = 1;
 
755
                                                if (next) {
 
756
                                                        GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Next segment to parse %s with init \n", next->url, buffer->url));
 
757
                                                        command->url_query.next_url = next->url;
 
758
                                                        command->url_query.next_url_init_or_switch_segment = buffer->url;
 
759
                                                        gf_list_rem(sb->input_buffer, 0);
 
760
                                                        gf_list_rem(sb->input_buffer, 0);
 
761
                                                } else {
 
762
                                                        GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Only one init segment to parse %s, need to wait\n", buffer->url));
 
763
                                                        command->url_query.next_url = NULL;
 
764
                                                }
 
765
                                        } else {
 
766
                                                GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Next segment to parse %s\n", buffer->url));
 
767
                                                command->url_query.next_url = buffer->url;
 
768
                                                gf_list_rem(sb->input_buffer, 0);
 
769
                                        }
 
770
                    sb->prev_buffer = buffer;
 
771
                } else {
 
772
                    command->url_query.next_url = NULL;
 
773
                    command->url_query.discontinuity_type = 0;
 
774
                }
 
775
            }
 
776
            break;
 
777
        case GF_NET_SERVICE_STATUS_PROXY:
 
778
            /* The parser is informing the proxy about its status changes:
 
779
                            - new track found 
 
780
                                - all tracks parsed
 
781
                                - connect/disconnect
 
782
                                - */
 
783
            if (command->status.is_add_media) {
 
784
                if (command->status.desc) {
 
785
                    gf_mse_source_buffer_store_track_desc(sb, (GF_ObjectDescriptor *)command->status.desc);
 
786
                } else {
 
787
                    /* this is the last add media, we can switch updating to false */
 
788
                    /* the first init segment was correctly processed */
 
789
                                        gf_mse_source_buffer_set_update(sb, GF_FALSE);
 
790
                    /* TODO: set active tracks and send addsourcebuffer event */
 
791
                    /* TODO: send media loadedmetadata event */
 
792
                }
 
793
                gf_term_add_media(sb->mediasource->service, command->status.desc, (command->status.desc ? GF_TRUE : GF_FALSE));
 
794
            }
 
795
            /* general connection/disconnection messages from the media parser (not track related) */
 
796
            else if (!command->status.channel) { 
 
797
                /* connection message */
 
798
                if (!command->status.is_disconnect) {
 
799
                    if (command->status.e == GF_OK) {
 
800
                        /* nothing needs to be done. Setup is done with final add media */
 
801
                        sb->parser_connected = GF_TRUE;
 
802
                        sb->mediasource->durationType = DURATION_INFINITY;
 
803
                        gf_mse_source_buffer_setup_tracks(sb);
 
804
                    } else {
 
805
                        /* wrong first init segment */
 
806
                        /* TODO: fire an error event */
 
807
                    }
 
808
                    gf_term_on_connect(sb->mediasource->service, command->status.channel, command->status.e);
 
809
                } else {
 
810
                    gf_term_on_disconnect(sb->mediasource->service, command->status.channel, command->status.e);
 
811
                }
 
812
            }
 
813
            /* channel (track related) specific connection/disconnection messages from the media parser */
 
814
            else {
 
815
                if (!command->status.is_disconnect) {
 
816
                    gf_term_on_connect(sb->mediasource->service, command->status.channel, command->status.e);
 
817
                } else {
 
818
                    gf_term_on_disconnect(sb->mediasource->service, command->status.channel, command->status.e);
 
819
                }
 
820
            }
 
821
            break;
 
822
        default:
 
823
            gf_term_on_command(sb->mediasource->service, command, GF_OK);
 
824
            break;
 
825
        }
 
826
        return GF_OK;
 
827
    }
 
828
}
 
829
 
 
830
/* Track Buffer Managment: 
 
831
 * - Access Units are parsed/demultiplexed from the SourceBuffer input buffer and placed into individual track buffers
 
832
 * - The parsing/demux is done in a separate thread (so access to the the track buffer is protected by a mutex)
 
833
 *
 
834
 * Track Buffer Length: number of Access Units */
 
835
#define MSE_TRACK_BUFFER_LENGTH 1000 
 
836
 
 
837
/* When an Access Unit can be released, we check if it needs to be kept or not in the track buffer */
 
838
GF_EXPORT
 
839
GF_Err gf_mse_track_buffer_release_packet(GF_HTML_Track *track) {
 
840
        GF_MSE_Packet *packet;
 
841
        gf_mx_p(track->buffer_mutex);
 
842
        packet = (GF_MSE_Packet *)gf_list_get(track->buffer, track->packet_index);
 
843
        if (packet) {
 
844
                track->packet_index++;
 
845
                if (gf_list_count(track->buffer) > MSE_TRACK_BUFFER_LENGTH) {
 
846
                        packet = (GF_MSE_Packet *)gf_list_get(track->buffer, 0);
 
847
                        track->packet_index--;
 
848
                        gf_list_rem(track->buffer, 0);
 
849
                        gf_free(packet->data);
 
850
                        gf_free(packet);
 
851
                }
 
852
        }
 
853
        gf_mx_v(track->buffer_mutex);
 
854
        return GF_OK;
 
855
}
 
856
 
 
857
/* Requests from the decoders to get the next Access Unit: we get it from the track buffer */
 
858
GF_EXPORT
 
859
GF_Err gf_mse_track_buffer_get_next_packet(GF_HTML_Track *track,
 
860
                                                                                        char **out_data_ptr, u32 *out_data_size, 
 
861
                                                                                        GF_SLHeader *out_sl_hdr, Bool *sl_compressed, 
 
862
                                                                                        GF_Err *out_reception_status, Bool *is_new_data)
 
863
{
 
864
        GF_MSE_Packet *packet;
 
865
        u32 count;
 
866
        gf_mx_p(track->buffer_mutex);
 
867
        count = gf_list_count(track->buffer);
 
868
        packet = (GF_MSE_Packet *)gf_list_get(track->buffer, track->packet_index);
 
869
        if (packet) {
 
870
                *out_data_ptr = packet->data;
 
871
                *out_data_size = packet->size;
 
872
                *out_sl_hdr = packet->sl_header;
 
873
                *sl_compressed = packet->is_compressed;
 
874
                *out_reception_status = packet->status;
 
875
                *is_new_data = packet->is_new_data;
 
876
                packet->is_new_data = GF_FALSE;
 
877
                GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE_IN] Sending AU #%d/%d to decoder with TS: %g \n", track->packet_index, count, (packet->sl_header.compositionTimeStamp*1.0/track->timescale)));
 
878
        } else {
 
879
                *out_data_ptr = NULL;
 
880
                *out_data_size = 0;
 
881
                *sl_compressed = GF_FALSE;
 
882
                *out_reception_status = GF_OK;
 
883
                *is_new_data = GF_FALSE;
 
884
                GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE_In] No AU for decoder\n"));
 
885
        }
 
886
        gf_mx_v(track->buffer_mutex);
 
887
        return GF_OK;
 
888
}
 
889
#endif