root/src/media_tools/saf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gf_saf_mux_new
  2. saf_stream_del
  3. gf_saf_mux_del
  4. saf_get_stream
  5. gf_saf_mux_stream_add
  6. gf_saf_mux_stream_rem
  7. gf_saf_mux_add_au
  8. gf_saf_mux_for_time

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2005-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / LASeR codec sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <gpac/internal/media_dev.h>
#include <gpac/bitstream.h>
#include <gpac/thread.h>
#include <gpac/list.h>

enum
{
        SAF_STREAM_HEADER = 1,
        SAF_STREAM_HEADER_PERMANENT = 2,
        SAF_END_OF_STREAM = 3,
        SAF_ACCESS_UNIT = 4,
        SAF_END_OF_SESSION = 5,
        SAF_CACHE_UNIT = 6,
        SAF_REMOTE_STREAM_HEADER = 7,
};


typedef struct
{
        char *data;
        u32 data_size;
        Bool is_rap;
        u32 ts;
} GF_SAFSample;

typedef struct
{
        u32 stream_id;
        u32 ts_resolution;
        u32 buffersize_db;
        u8 stream_type, object_type;
        char *mime_type;
        char *remote_url;

        char *dsi;
        u32 dsi_len;

        GF_List *aus;
        /*0: not declared yet; 1: declared; (1<<1) : done but end of stream not sent yet*/
        u32 state;
        u32 last_au_sn, last_au_ts;
} GF_SAFStream;

struct __saf_muxer
{
        GF_List *streams;
        /*0: nothing to do, 1: should regenerate, (1<<1): end of session has been sent*/
        u32 state;
        GF_Mutex *mx;
};

GF_SAFMuxer *gf_saf_mux_new()
{
        GF_SAFMuxer *mux;
        GF_SAFEALLOC(mux, GF_SAFMuxer);
        if (!mux) return NULL;
        mux->mx = gf_mx_new("SAF");
        mux->streams = gf_list_new();
        return mux;
}

static void saf_stream_del(GF_SAFStream *str)
{
        if (str->mime_type) gf_free(str->mime_type);
        if (str->remote_url) gf_free(str->remote_url);
        if (str->dsi) gf_free(str->dsi);

        while (gf_list_count(str->aus)) {
                GF_SAFSample *au = (GF_SAFSample *)gf_list_last(str->aus);
                gf_list_rem_last(str->aus);
                if (au->data) gf_free(au->data);
                gf_free(au);
        }
        gf_list_del(str->aus);
        gf_free(str);
}

void gf_saf_mux_del(GF_SAFMuxer *mux)
{
        while (gf_list_count(mux->streams)) {
                GF_SAFStream *str = (GF_SAFStream *)gf_list_last(mux->streams);
                gf_list_rem_last(mux->streams);
                saf_stream_del(str);
        }
        gf_list_del(mux->streams);
        gf_mx_del(mux->mx);
        gf_free(mux);
}

static GFINLINE GF_SAFStream *saf_get_stream(GF_SAFMuxer *mux, u32 stream_id)
{
        GF_SAFStream *str;
        u32 i=0;
        while ( (str = (GF_SAFStream *)gf_list_enum(mux->streams, &i)) ) {
                if (str->stream_id==stream_id) return str;
        }
        return NULL;
}

GF_Err gf_saf_mux_stream_add(GF_SAFMuxer *mux, u32 stream_id, u32 ts_res, u32 buffersize_db, u8 stream_type, u8 object_type, char *mime_type, char *dsi, u32 dsi_len, char *remote_url)
{
        GF_SAFStream *str = saf_get_stream(mux, stream_id);
        if (str) return GF_BAD_PARAM;

        if (mux->state == 2) return GF_BAD_PARAM;

        gf_mx_p(mux->mx);

        GF_SAFEALLOC(str, GF_SAFStream);
        if (!str) return GF_OUT_OF_MEM;
        str->stream_id = stream_id;
        str->ts_resolution = ts_res;
        str->buffersize_db = buffersize_db;
        str->stream_type = stream_type;
        str->object_type = object_type;
        if (mime_type) {
                str->mime_type = gf_strdup(mime_type);
                str->stream_type = str->object_type = 0xFF;
        }
        str->dsi_len = dsi_len;
        if (dsi_len) {
                str->dsi = (char *) gf_malloc(sizeof(char)*dsi_len);
                memcpy(str->dsi, dsi, sizeof(char)*dsi_len);
        }
        if (remote_url) str->remote_url = gf_strdup(remote_url);
        str->aus = gf_list_new();
        mux->state = 0;
        gf_list_add(mux->streams, str);
        gf_mx_v(mux->mx);
        return GF_OK;
}

GF_Err gf_saf_mux_stream_rem(GF_SAFMuxer *mux, u32 stream_id)
{
        GF_SAFStream *str = saf_get_stream(mux, stream_id);
        if (!str) return GF_BAD_PARAM;
        if (mux->state == 2) return GF_BAD_PARAM;

        gf_mx_p(mux->mx);
        str->state |= 2;
        mux->state = 1;
        gf_mx_v(mux->mx);
        return GF_OK;
}

GF_Err gf_saf_mux_add_au(GF_SAFMuxer *mux, u32 stream_id, u32 CTS, char *data, u32 data_len, Bool is_rap)
{
        GF_SAFSample *au;
        GF_SAFStream *str = saf_get_stream(mux, stream_id);
        if (!str) return GF_BAD_PARAM;
        if (mux->state == 2) return GF_BAD_PARAM;

        gf_mx_p(mux->mx);

        GF_SAFEALLOC(au, GF_SAFSample);
        if (!au) return GF_OUT_OF_MEM;
        au->data = data;
        au->data_size = data_len;
        au->is_rap = is_rap;
        au->ts = CTS;
        mux->state = 1;

        gf_list_add(str->aus, au);
        gf_mx_v(mux->mx);
        return GF_OK;
}


GF_Err gf_saf_mux_for_time(GF_SAFMuxer *mux, u32 time_ms, Bool force_end_of_session, char **out_data, u32 *out_size)
{
        u32 i, count, dlen;
        char *data;
        GF_SAFStream *str;
        GF_SAFSample*au;
        GF_BitStream *bs, *payload;

        *out_data = NULL;
        *out_size = 0;

        gf_mx_p(mux->mx);
        if (!force_end_of_session && (mux->state!=1)) {
                gf_mx_v(mux->mx);
                return GF_OK;
        }

        bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);

        count = gf_list_count(mux->streams);

        /*1: write all stream headers*/
        for (i=0; i<count; i++) {
                str = (GF_SAFStream *)gf_list_get(mux->streams, i);
                if (str->state & 1) continue;

                au = (GF_SAFSample *)gf_list_get(str->aus, 0);

                /*write stream declaration*/
                payload = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
                gf_bs_write_int(payload, str->remote_url ? SAF_REMOTE_STREAM_HEADER : SAF_STREAM_HEADER, 4);
                gf_bs_write_int(payload, str->stream_id, 12);

                gf_bs_write_u8(payload, str->object_type);
                gf_bs_write_u8(payload, str->stream_type);
                gf_bs_write_int(payload, str->ts_resolution, 24);
                gf_bs_write_u16(payload, str->buffersize_db);
                if (str->mime_type) {
                        u32 len = (u32) strlen(str->mime_type);
                        gf_bs_write_u16(payload, len);
                        gf_bs_write_data(payload, str->mime_type, len);
                }
                if (str->remote_url) {
                        u32 len = (u32) strlen(str->remote_url);
                        gf_bs_write_u16(payload, len);
                        gf_bs_write_data(payload, str->remote_url, len);
                }
                if (str->dsi) {
                        gf_bs_write_data(payload, str->dsi, str->dsi_len);
                }

                gf_bs_get_content(payload, &data, &dlen);
                gf_bs_del(payload);

                /*write SAF packet header*/
                gf_bs_write_int(bs, 1, 1);
                gf_bs_write_int(bs, 0, 15);
                gf_bs_write_int(bs, 0, 1);
                gf_bs_write_int(bs, 1, 1);
                gf_bs_write_int(bs, au ? au->ts : 0, 30);
                gf_bs_write_int(bs, dlen, 16);
                gf_bs_write_data(bs, data, dlen);
                gf_free(data);

                /*mark as signaled*/
                str->state |= 1;
        }

        /*write all pending AUs*/
        while (1) {
                GF_SAFStream *src = NULL;
                u32 mux_time = time_ms;

                for (i=0; i<count; i++) {
                        str = (GF_SAFStream*)gf_list_get(mux->streams, i);
                        au = (GF_SAFSample*)gf_list_get(str->aus, 0);
                        if (au && (au->ts*1000 < mux_time*str->ts_resolution)) {
                                mux_time = 1000*au->ts/str->ts_resolution;
                                src = str;
                        }
                }

                if (!src) break;

                au = (GF_SAFSample*)gf_list_get(src->aus, 0);
                gf_list_rem(src->aus, 0);

                /*write stream declaration*/
                gf_bs_write_int(bs, au->is_rap ? 1 : 0, 1);
                gf_bs_write_int(bs, src->last_au_sn, 15);
                gf_bs_write_int(bs, 0, 1);
                gf_bs_write_int(bs, 1, 1);
                gf_bs_write_int(bs, au->ts, 30);
                gf_bs_write_u16(bs, 2+au->data_size);
                gf_bs_write_int(bs, SAF_ACCESS_UNIT, 4);
                gf_bs_write_int(bs, src->stream_id, 12);
                gf_bs_write_data(bs, au->data, au->data_size);

                src->last_au_sn ++;
                src->last_au_ts = au->ts;
                gf_free(au->data);
                gf_free(au);
        }

        /*3: write all end of stream*/
        for (i=0; i<count; i++) {
                str = (GF_SAFStream*)gf_list_get(mux->streams, i);
                /*mark as signaled*/
                if (!(str->state & 2)) continue;
                if (gf_list_count(str->aus)) continue;

                /*write stream declaration*/
                gf_bs_write_int(bs, 1, 1);
                gf_bs_write_int(bs, str->last_au_sn, 15);
                gf_bs_write_int(bs, 0, 1);
                gf_bs_write_int(bs, 1, 1);
                gf_bs_write_int(bs, str->last_au_ts, 30);
                gf_bs_write_int(bs, 2, 16);
                gf_bs_write_int(bs, SAF_END_OF_STREAM, 4);
                gf_bs_write_int(bs, str->stream_id, 12);

                /*remove stream*/
                gf_list_rem(mux->streams, i);
                i--;
                count--;
                saf_stream_del(str);
        }
        mux->state = 0;
        if (force_end_of_session) {
                gf_bs_write_int(bs, 1, 1);
                gf_bs_write_int(bs, 0, 15);
                gf_bs_write_int(bs, 0, 1);
                gf_bs_write_int(bs, 1, 1);
                gf_bs_write_int(bs, 0, 30);
                gf_bs_write_int(bs, 2, 16);
                gf_bs_write_int(bs, SAF_END_OF_SESSION, 4);
                gf_bs_write_int(bs, 0, 12);
                mux->state = 2;
        }
        gf_bs_get_content(bs, out_data, out_size);
        gf_bs_del(bs);
        gf_mx_v(mux->mx);
        return GF_OK;
}

/* [<][>][^][v][top][bottom][index][help] */