root/modules/libplayer/libplayer.c

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

DEFINITIONS

This source file includes following definitions.
  1. LIBPLAYER_RegisterMimeTypes
  2. LIBPLAYER_CanHandleURL
  3. on_libplayer_event
  4. LIBPLAYER_ConnectService
  5. LIBPLAYER_CloseService
  6. LIBPLAYER_GetServiceDesc
  7. LIBPLAYER_ServiceCommand
  8. LIBPLAYER_ConnectChannel
  9. LIBPLAYER_DisconnectChannel
  10. LIBPLAYER_CanHandleURLInService
  11. LIBPLAYER_AttachStream
  12. LIBPLAYER_DetachStream
  13. LIBPLAYER_GetCapabilities
  14. LIBPLAYER_SetCapabilities
  15. LIBPLAYER_CanHandleStream
  16. LIBPLAYER_GetName
  17. LIBPLAYER_Control
  18. QueryInterfaces
  19. LoadInterface
  20. ShutdownInterface

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2005-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / Dummy input module
 *
 *  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/modules/service.h>
#include <gpac/modules/codec.h>
/*for GF_STREAM_PRIVATE_SCENE definition*/
#include <gpac/constants.h>
#include <gpac/download.h>

//#define TEST_LIBPLAYER

#ifndef TEST_LIBPLAYER

#ifdef WIN32
typedef u32 uint32_t;
typedef u8 uint8_t;
typedef s8 int8_t;
typedef s32 off_t;
#endif

#include "player.h"

#endif

// variable used to detect the number of libplayer instances created - up to 2 instances
static int libplayer_id = 0;
//! unfortunately, saving data would not be a good solution for Mosaic Mode in ESG Application since the position changes everytime user
//! uses the navigation button
// value for input output windows, when save_data_instance1 equals to 1 <=> the second instance is already created with the correct size,
// save these values in in_instance1 and out_instance1 so that we do not need to recalculate every time
//~ static video_rect_t in_instance1, out_instance1;
//~ static save_data_instance1 = 0;

// variable use to detect whether a dvb instance has already started for instance 1
static int start_dvb = 0;

enum
{
        PLAYER_FILE = 0,
        PLAYER_DVB = 1
};


typedef struct
{
        /*the service we're responsible for*/
        GF_ClientService *service;
        u32 init;
        u32 state;
        u32 player_id;
        u32 player_type;
        u32 width;
        u32 height;
        char *url;
#ifndef TEST_LIBPLAYER
        player_t *player;
#endif

} LibPlayerIn;


static const char * LIBPLAYER_MIME_TYPES[] = {
        "video/x-mpeg", "mpg mpeg mp2 mpa mpe mpv2 ts", "MPEG 1/2 Movies",
        "video/x-mpeg-systems", "mpg mpeg mp2 mpa mpe mpv2", "MPEG 1/2 Movies",
        "audio/basic", "snd au", "Basic Audio",
        "audio/x-wav", "wav", "WAV Audio",
        "audio/vnd.wave", "wav", "WAV Audio",
        "video/x-ms-asf", "asf wma wmv asx asr", "WindowsMedia Movies",
        "video/x-ms-wmv", "asf wma wmv asx asr", "WindowsMedia Movies",
        "video/x-msvideo", "avi", "AVI Movies",
        "video/x-ms-video", "avi", "AVI Movies",
        "video/avi", "avi", "AVI Movies",
        "video/vnd.avi", "avi", "AVI Movies",
        "video/H263", "h263 263", "H263 Video",
        "video/H264", "h264 264", "H264 Video",
        "video/MPEG4", "cmp", "MPEG-4 Video",
        "video/mp4", "mp4", "MPEG-4 Movie",
        "video/quicktime", "mov qt", "QuickTime Movies",
        "video/webm", "webm", "Google WebM Movies",
        "audio/webm", "webm", "Google WebM Music",
        NULL
};


static u32 LIBPLAYER_RegisterMimeTypes(const GF_InputService *plug) {
        u32 i;
        if (!plug)
                return 0;
        for (i = 0 ; LIBPLAYER_MIME_TYPES[i] ; i+=3)
                gf_service_register_mime(plug, LIBPLAYER_MIME_TYPES[i], LIBPLAYER_MIME_TYPES[i+1], LIBPLAYER_MIME_TYPES[i+2]);
        return i / 3;
}

Bool LIBPLAYER_CanHandleURL(GF_InputService *plug, const char *url)
{
        char *sExt = strrchr(url, '.');
        if (sExt) {
                u32 i;
                Bool ok = 0;
                char *cgi_par;
                // case dvb
                if (!strnicmp(url, "dvb://", 6)) return 1;
                if (!strnicmp(sExt, ".gz", 3)) sExt = strrchr(sExt, '.');
                if (!strnicmp(url, "rtsp://", 7)) return 0;
                sExt++;

                cgi_par = strchr(sExt, '?');
                if (cgi_par) cgi_par[0] = 0;

                for (i = 0 ; LIBPLAYER_MIME_TYPES[i] ; i+=3) {
                        if (strstr(LIBPLAYER_MIME_TYPES[i+1], sExt)) {
                                ok=1;
                                break;
                        }
                }
                if (cgi_par) cgi_par[0] = '?';
                if (ok) return 1;
        }

        return 0;
}

#ifndef TEST_LIBPLAYER

static int on_libplayer_event(player_event_t e, void *data)
{
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerEvent] Received event %d\n", e));

        switch (e) {
        case PLAYER_EVENT_PLAYBACK_FINISHED:
                player_playback_stop(data);
                player_playback_start(data);
                break;
        case PLAYER_EVENT_FE_HAS_LOCK:
                break;
        case PLAYER_EVENT_FE_TIMEDOUT:
                break;
        case PLAYER_EVENT_VIDEO_PICTURE:
                break;
        default:
                break;
        }

        return 0;
}



#endif

GF_Err LIBPLAYER_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url)
{
        LibPlayerIn *read = (LibPlayerIn *) plug->priv;
#ifndef TEST_LIBPLAYER
        mrl_t *mrl = NULL;
#endif

        GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[LibPlayerIN] Connecting\n"));

        if (!read || !serv || !url) return GF_BAD_PARAM;

        if (!strnicmp(url, "libplayer://", 12)) url+=12;

        if (!read->init) {
                read->init=1;
                /* libplayer init with default width/height */
                read->width = 80;
                read->height = 20;
                read->url = url;
                read->player_id = libplayer_id;
                read->player_type = PLAYER_FILE;

#ifndef TEST_LIBPLAYER
                read->player = player_init(PLAYER_TYPE_DUMMY, PLAYER_AO_AUTO, PLAYER_VO_AUTO, PLAYER_MSG_INFO, read->player_id, on_libplayer_event);

                if (!read->player) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[LibPlayerIN] Failed to instanciate libplayer instance %d\n", read->player_id));
                        gf_service_connect_ack(serv, NULL, GF_REMOTE_SERVICE_ERROR);
                        return GF_OK;
                }
#endif
                libplayer_id++;
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] Opening URL %s for Player instance %d\n", url, read->player_id));
        }

#ifndef TEST_LIBPLAYER
        mrl = NULL;

        // dvb
        if (!strnicmp(url, "dvb://", 6)) {
                read->player_type = PLAYER_DVB;
                mrl_resource_dvb_args_t *mrl_dvb_args;
                mrl_dvb_args = calloc(1, sizeof(mrl_resource_dvb_args_t));
                char *frequency;

                // fetch frequency
                if (frequency = strchr(url+6, '@')) {
                        char *enc, *pid;
                        mrl_dvb_args->frequency = atoi(frequency+1);

                        /*
                         * video
                         */
                        // video codec
                        if (enc = strstr(url+6, "mpeg2")) {
                                mrl_dvb_args->video_enc = PLAYER_VIDEO_MPEG2;
                        }
                        else if (enc = strstr(url+6, "h264")) {
                                mrl_dvb_args->video_enc = PLAYER_VIDEO_H264;
                        }
                        else {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[LibPlayerIN] Unknown video encoding\n"));
                                mrl_dvb_args->video_enc = PLAYER_VIDEO_UNKNOWN;
                        }

                        // video PID
                        if (mrl_dvb_args->video_enc != PLAYER_VIDEO_UNKNOWN) {
                                pid = strchr(enc, ':');
                                mrl_dvb_args->video_pid = atoi(pid+1);
                        }

                        /*
                         * audio
                         */
                        // audio codec
                        if (enc = strstr(url+6, "mp2")) {
                                mrl_dvb_args->audio_enc = PLAYER_AUDIO_MP2;
                        }
                        else if (enc = strstr(url+6, "ac3")) {
                                mrl_dvb_args->audio_enc = PLAYER_AUDIO_AC3;
                        }
                        else {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[LibPlayerIN] Unknown audio encoding\n"));
                                mrl_dvb_args->audio_enc = PLAYER_AUDIO_UNKNOWN;
                        }

                        // audio PID
                        if (mrl_dvb_args->audio_enc != PLAYER_AUDIO_UNKNOWN) {
                                pid = strchr(enc, ':');
                                mrl_dvb_args->audio_pid = atoi(pid+1);
                        }

                        if (mrl_dvb_args->video_enc == PLAYER_VIDEO_UNKNOWN && mrl_dvb_args->audio_enc == PLAYER_AUDIO_UNKNOWN) {
                                GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[LibPlayerIN] Unknown video and audio encoding\n"));
                                free(mrl_dvb_args);
                                return GF_BAD_PARAM;
                        }
                }
                else {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[LibPlayerIN] Unknown frequency\n"));
                        free(mrl_dvb_args);
                        return GF_BAD_PARAM;
                }

                // player instance 1 has not starter yet in dvb case <=> player instance 1 is not created yet
                if (start_dvb == 0) {
                        mrl = mrl_new(read->player, MRL_RESOURCE_DVB, mrl_dvb_args);
                        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] MRL created for DVB\n"));

                        // player has already started, zapping case, make sure the player is not recreated
                } else {
                        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] Starting DVB PES filtering\n"));
                        player_dvb_pes_filter_start(read->player, mrl_dvb_args->video_enc, mrl_dvb_args->video_pid, mrl_dvb_args->audio_enc, mrl_dvb_args->audio_pid);
                }

        }
        else if (!strnicmp(url, "file://", 7) || !strstr(url, "://")) {
                mrl_resource_local_args_t *mrl_args;
                mrl_args = calloc(1, sizeof(mrl_resource_local_args_t));
                if (!strnicmp(url, "file://", 7)) {
                        mrl_args->location = strdup(url + 7);
                }  else {
                        mrl_args->location = strdup(url);
                }
                mrl = mrl_new (read->player, MRL_RESOURCE_FILE, mrl_args);

        }

        // only for DVB case to make sure player is only set once
        if (start_dvb == 0) {
                if (!mrl) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[LibPlayerIN] Failed to create MRL for url %s\n", url));
                        gf_service_connect_ack(serv, NULL, GF_URL_ERROR);
                        return GF_OK;
                }

                player_mrl_set(read->player, mrl);
        }

#endif
        read->state = 0;
        read->service = serv;

        /*ACK connection is OK*/
        gf_service_connect_ack(serv, NULL, GF_OK);


        /*setup LIBPLAYER object descriptor*/
        {
                GF_ESD *esd;
                GF_ObjectDescriptor *od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
                od->objectDescriptorID = 1+read->player_id;

                esd = gf_odf_desc_esd_new(0);
                esd->ESID = 1+read->player_id;
                esd->slConfig->timestampResolution = 1000;
                esd->decoderConfig->streamType = GF_STREAM_PRIVATE_MEDIA;
                esd->decoderConfig->objectTypeIndication = GPAC_OTI_PRIVATE_MEDIA_LIBPLAYER;
#ifndef TEST_LIBPLAYER
                esd->decoderConfig->decoderSpecificInfo->data = read;
#endif

                gf_list_add(od->ESDescriptors, esd);
                gf_service_declare_media(read->service, (GF_Descriptor*)od, 0);
        }

        return GF_OK;
}

GF_Err LIBPLAYER_CloseService(GF_InputService *plug)
{
        LibPlayerIn *read = (LibPlayerIn *) plug->priv;

#ifndef TEST_LIBPLAYER
        // only disconnect if
        if (read->player_type == PLAYER_FILE) {
                player_playback_stop(read->player);
                fprintf(stderr, "[LibPlayerIN]player_playback_stop for instance %d\n", read->player_id);
                player_uninit(read->player);
                fprintf(stderr, "[LibPlayerIN]player_uninit for instance %d\n", read->player_id);
                read->player = NULL;
                libplayer_id--;

                read->state = 0;

                gf_service_disconnect_ack(read->service, NULL, GF_OK);
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIn] Closing libplayer instance %d\n", read->player_id));



                // channel zapping dvb case, don't disconnect service
        } else {
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIn] Don't close service libplayer instance %d, use this instance for channel zapping\n", read->player_id));
        }

        return GF_OK;
#endif
}

/*Dummy input just send a file name, no multitrack to handle so we don't need to check sub_url nor expected type*/
static GF_Descriptor *LIBPLAYER_GetServiceDesc(GF_InputService *plug, u32 expect_type, const char *sub_url)
{
        return NULL;
}


GF_Err LIBPLAYER_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
{
        LibPlayerIn *read = (LibPlayerIn *) plug->priv;
        unsigned long prop = 0;
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] ServiceCommand for instance %d, read->state=%d\n", read->player_id, read->state));
        if (!com->base.on_channel) return GF_NOT_SUPPORTED;

        if (com->command_type==GF_NET_SERVICE_HAS_AUDIO) return GF_NOT_SUPPORTED;

        switch (com->command_type) {
        case GF_NET_CHAN_SET_PULL:
                return GF_NOT_SUPPORTED;
        case GF_NET_CHAN_INTERACTIVE:
                return GF_OK;
        /*since data is file-based, no padding is needed (decoder plugin will handle it itself)*/
        case GF_NET_CHAN_SET_PADDING:
                return GF_OK;
        case GF_NET_CHAN_BUFFER:
                return GF_OK;
                com->buffer.max = com->buffer.min = 0;
                return GF_OK;
        case GF_NET_CHAN_DURATION:
                /*this module is not made for updates, use undefined duration*/
                com->duration.duration = -1;
                return GF_OK;
        case GF_NET_CHAN_PLAY:
                if (read->state==0) {
#ifndef TEST_LIBPLAYER
                        if ((read->player_id == 0) && (read->player_type == PLAYER_DVB) && (start_dvb == 1)) {
                                GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] Instance %d has already started, zapping mode\n", read->player_id));

                        } else {
                                player_playback_start(read->player);
                                if ((read->player_id == 0) && (read->player_type == PLAYER_DVB)) {
                                        start_dvb = 1;
                                }

                                read->state = 1;
                                GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] Starting playback for instance %d\n", read->player_id));
                        }
#endif
                }

                return GF_OK;
        case GF_NET_CHAN_STOP:
                if (read->state==1) {
#ifndef TEST_LIBPLAYER
                        // channel zapping, don't stop channel
                        if ((read->player_id == 0) && (read->player_type == PLAYER_DVB) && (start_dvb = 1)) {
                                GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] Instance %d is in zapping mode, don't stop channel\n", read->player_id));
                        } else {
                                player_playback_stop(read->player);
                                read->state = 0;
                                GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] Stopping playback for instance %d\n", read->player_id));
                        }
#endif
                }
                return GF_OK;
        case GF_NET_CHAN_CONFIG:
                return GF_OK;
        case GF_NET_CHAN_GET_DSI:
                com->get_dsi.dsi = NULL;
                com->get_dsi.dsi_len = 0;
                return GF_OK;
        }
        return GF_OK;
}

GF_Err LIBPLAYER_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const char *url, Bool upstream)
{
        u32 ESID;
        LibPlayerIn *read = (LibPlayerIn *) plug->priv;
        sscanf(url, "ES_ID=%ud", &ESID);
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] instance %d connect channel %d\n", read->player_id, ESID));
        if (ESID != 1+read->player_id) {
                gf_service_connect_ack(read->service, channel, GF_STREAM_NOT_FOUND);
        } else {
                gf_service_connect_ack(read->service, channel, GF_OK);
        }
        return GF_OK;
}

GF_Err LIBPLAYER_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
        LibPlayerIn *read = (LibPlayerIn *) plug->priv;
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] instance %d disconnect channel\n", read->player_id));
        gf_service_disconnect_ack(read->service, channel, GF_OK);
        return GF_OK;
}



Bool LIBPLAYER_CanHandleURLInService(GF_InputService *plug, const char *url)
{
        return 0;
        //return 1;
}

static GF_Err LIBPLAYER_AttachStream(GF_BaseDecoder *dec, GF_ESD *esd)
{
        LibPlayerIn *read;

        if (dec->privateStack) return GF_BAD_PARAM;
        if (!esd->decoderConfig->decoderSpecificInfo) return GF_BAD_PARAM;
        if (!esd->decoderConfig->decoderSpecificInfo->data) return GF_BAD_PARAM;
        read = (LibPlayerIn *) esd->decoderConfig->decoderSpecificInfo->data;
        if (esd->ESID!=1+read->player_id) return GF_BAD_PARAM;
        dec->privateStack = read;

        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerDEC] AttachStream for instance %d\n", read->player_id));
        esd->decoderConfig->decoderSpecificInfo->data = NULL;
        return GF_OK;
}

static GF_Err LIBPLAYER_DetachStream(GF_BaseDecoder *dec, u16 ES_ID)
{
        LibPlayerIn *player = dec->privateStack;
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerDEC] DetachStream for instance %d\n", player ? player->player_id : -1));
        dec->privateStack = NULL;
        return GF_OK;
}
static GF_Err LIBPLAYER_GetCapabilities(GF_BaseDecoder *dec, GF_CodecCapability *capability)
{
        LibPlayerIn *read = dec->privateStack;
        //GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerDEC] GetCapabilities\n"));
        switch (capability->CapCode) {
        case GF_CODEC_WIDTH:
                capability->cap.valueInt = read->width;
                break;
        case GF_CODEC_HEIGHT:
                capability->cap.valueInt = read->height;
                break;
        }
        return GF_OK;
}
static GF_Err LIBPLAYER_SetCapabilities(GF_BaseDecoder *dec, GF_CodecCapability capability)
{
        return GF_NOT_SUPPORTED;
}
static u32 LIBPLAYER_CanHandleStream(GF_BaseDecoder *dec, u32 StreamType, GF_ESD *esd, u8 PL)
{
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerDEC] CanHandleStream\n"));
        if (StreamType!=GF_STREAM_PRIVATE_MEDIA) return GF_CODEC_NOT_SUPPORTED;
        /*don't reply to media type queries*/
        if (!esd) return GF_CODEC_NOT_SUPPORTED;
        if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_PRIVATE_MEDIA_LIBPLAYER) return GF_CODEC_SUPPORTED;
        return GF_CODEC_NOT_SUPPORTED;
}
static const char *LIBPLAYER_GetName(GF_BaseDecoder *dec)
{
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerDEC] GetName\n"));
        return "LibPlayer decoder";
}

static GF_Err LIBPLAYER_Control(GF_PrivateMediaDecoder *dec, Bool mute, GF_Window *src, GF_Window *dst)
{
#ifndef TEST_LIBPLAYER
        video_rect_t in, out;
        LibPlayerIn *read = dec->privateStack;
        u32 width, height;

        if (!read) return GF_OK;
        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerDEC] Control instance %d\n",read->player_id));
        //! unfortunately, saving data would not be a good solution for Mosaic Mode in ESG Application since the position changes everytime user
        //! uses the navigation button
        //~ if (read->player_id == 1 && save_data_instance1 == 1) {
        //~ fprintf(stderr, "in here for save data instance\n");
        //~ player_video_io_windows_set(read->player, &in_instance1, &out_instance1);
        //~
        //~ return GF_OK;
        //~
        //~ } else {
        width = mrl_get_property(read->player, NULL, MRL_PROPERTY_VIDEO_WIDTH);
        height = mrl_get_property(read->player, NULL, MRL_PROPERTY_VIDEO_HEIGHT);
        //~ }



        if((width != read->width) || (height != read->height))  {
                fprintf(stderr, "in here for video size changed\t");
                fprintf(stderr, "width %d read->width %d height %d read->height %d\n", width, read->width, height, read->height);
                GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerDEC] video size changed to width %d - height %d\n", width, height));
                if (width && height) {
                        read->width = width;
                        read->height = height;
                }
                return GF_BUFFER_TOO_SMALL;
        }

        in.x = src->x;
        in.y = src->y;
        in.w = src->w;
        in.h = src->h;
        out.x = dst->x;
        out.y = dst->y;
        out.w = dst->w;
        out.h = dst->h;
        player_video_io_windows_set(read->player, &in, &out);

        //! unfortunately, saving data would not be a good solution for Mosaic Mode in ESG Application since the position changes everytime user
        //! uses the navigation button
        //~ if (read->player_id == 1) {
        //~ in_instance1 = in;
        //~ //  //~ out_instance1.w = out.w;
        //~ //  //~ out_instance1.h = out.h;
        //~ out_instance1 = out;
        //~ save_data_instance1 = 1;
        //~ }
        //~

#endif

        GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerDEC] Repositioning video src %d %d %d %d - dest %d %d %d %d\n", src->x, src->y, src->w, src->h, dst->x, dst->y, dst->w, dst->h) );
        return GF_OK;
}


GPAC_MODULE_EXPORT
const u32 *QueryInterfaces()
{
        static u32 si [] = {
                GF_NET_CLIENT_INTERFACE,
                GF_PRIVATE_MEDIA_DECODER_INTERFACE,
                0
        };
        return si;
}

GPAC_MODULE_EXPORT
GF_BaseInterface *LoadInterface(u32 InterfaceType)
{
        if (InterfaceType == GF_NET_CLIENT_INTERFACE) {
                LibPlayerIn *read;
                GF_InputService *plug;
                GF_SAFEALLOC(plug, GF_InputService);
                memset(plug, 0, sizeof(GF_InputService));
                GF_REGISTER_MODULE_INTERFACE(plug, GF_NET_CLIENT_INTERFACE, "LibPlayer Input", "gpac distribution")

                plug->RegisterMimeTypes = LIBPLAYER_RegisterMimeTypes;
                plug->CanHandleURL = LIBPLAYER_CanHandleURL;
                plug->ConnectService = LIBPLAYER_ConnectService;
                plug->CloseService = LIBPLAYER_CloseService;
                plug->GetServiceDescriptor = LIBPLAYER_GetServiceDesc;
                plug->ConnectChannel = LIBPLAYER_ConnectChannel;
                plug->DisconnectChannel = LIBPLAYER_DisconnectChannel;
                plug->ServiceCommand = LIBPLAYER_ServiceCommand;
                plug->CanHandleURLInService = LIBPLAYER_CanHandleURLInService;

                GF_SAFEALLOC(read, LibPlayerIn);
                plug->priv = read;
                return (GF_BaseInterface *)plug;

        } else if (InterfaceType == GF_PRIVATE_MEDIA_DECODER_INTERFACE) {
                GF_PrivateMediaDecoder *ifce;

                GF_SAFEALLOC(ifce, GF_PrivateMediaDecoder);
                GF_REGISTER_MODULE_INTERFACE(ifce, GF_PRIVATE_MEDIA_DECODER_INTERFACE, "LibPlayer Decoder", "gpac distribution")

                /*setup our own interface*/
                ifce->AttachStream = LIBPLAYER_AttachStream;
                ifce->DetachStream = LIBPLAYER_DetachStream;
                ifce->GetCapabilities = LIBPLAYER_GetCapabilities;
                ifce->SetCapabilities = LIBPLAYER_SetCapabilities;
                ifce->Control = LIBPLAYER_Control;
                ifce->CanHandleStream = LIBPLAYER_CanHandleStream;
                ifce->GetName = LIBPLAYER_GetName;
                return (GF_BaseInterface *) ifce;
        }
        return NULL;
}

GPAC_MODULE_EXPORT
void ShutdownInterface(GF_BaseInterface *bi)
{
        if (bi->InterfaceType==GF_NET_CLIENT_INTERFACE) {
                GF_InputService *ifcn = (GF_InputService*)bi;
                LibPlayerIn *read = (LibPlayerIn*)ifcn->priv;
                gf_free(read);
                gf_free(bi);
        } else if (bi->InterfaceType == GF_PRIVATE_MEDIA_DECODER_INTERFACE) {
                gf_free(bi);
        }
}

GPAC_MODULE_STATIC_DECLARATION( libplayer )

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