blob: b4cf7c8939ccdb4bd02e2f0fbf735f0b57c9cdf2 [file] [log] [blame]
/*
* Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All rights reserved.
*
*/
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>
#include "playengine.h"
#ifdef PREPARE_WINDOW_MESSAGE
static GstBusSyncReply bus_sync_cb(GstBus * bus, GstMessage * message,
gpointer user_data)
{
play_engine *engine = (play_engine *)user_data;
if (!engine)
return GST_BUS_PASS;
if (!gst_is_video_overlay_prepare_window_handle_message(message))
return GST_BUS_PASS;
#ifndef ENABLE_OVERLAY_INTERNEL_WINDOW
if (engine->video_window_handle != 0) {
GstVideoOverlay *overlay;
overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC (message));
gst_video_overlay_set_window_handle(overlay, engine->video_window_handle);
} else {
g_warning("No window created for video!\n");
if (engine->error_cb)
engine->error_cb("No window created for video!");
}
#endif
gst_message_unref(message);
return GST_BUS_DROP;
}
#endif
/* Get metadata information. */
static void get_metadata_tag(const GstTagList * list, const gchar * tag,
gpointer data)
{
gint count = gst_tag_list_get_tag_size(list, tag);
gint i = 0;
play_engine *engine = (play_engine *)data;
if (!engine)
return;
imx_metadata *meta = &engine->meta;
for (i = 0; i < count; i++) {
const GValue *val = gst_tag_list_get_value_index (list, tag, i);
//g_print ("\t%20s : tag of type %s\n", tag, G_VALUE_TYPE_NAME (val));
if (G_VALUE_HOLDS_STRING (val)) {
const gchar *str = g_value_get_string (val);
if (str) {
if( strncmp(gst_tag_get_nick(tag), "container format", 16) == 0 ) {
strncpy(meta->container, str, sizeof(meta->container));
meta->container[sizeof(meta->container) - 1] = '\0';
}
if (strncmp(gst_tag_get_nick(tag), "location", 8) == 0) {
strncpy(meta->pathname, str, sizeof(meta->pathname));
meta->pathname[sizeof(meta->pathname) - 1] = '\0';
}
if (strncmp(gst_tag_get_nick(tag), "title", 5) == 0) {
strncpy(meta->title, str, sizeof(meta->title));
meta->title[sizeof(meta->title) - 1] = '\0';
}
if (strncmp(gst_tag_get_nick(tag), "artist", 6) == 0) {
strncpy(meta->artist, str, sizeof(meta->artist));
meta->artist[sizeof(meta->artist) - 1] = '\0';
}
if (strncmp(gst_tag_get_nick(tag), "album", 5) == 0) {
strncpy(meta->album, str, sizeof(meta->album));
meta->album[sizeof(meta->album) - 1] = '\0';
}
if (strncmp(gst_tag_get_nick(tag), "date", 4) == 0) {
strncpy(meta->year, str, sizeof(meta->year));
meta->year[sizeof(meta->year) - 1] = '\0';
}
if (strncmp(gst_tag_get_nick(tag), "genre", 5) == 0) {
strncpy(meta->genre, str, sizeof(meta->genre));
meta->genre[sizeof(meta->genre) - 1] = '\0';
}
#ifdef GET_STREAM_INFO_FROM_TAGS
if (strncmp(gst_tag_get_nick(tag), "audio codec", 11) == 0) {
strncpy(meta->audiocodec, str, sizeof(meta->audiocodec));
meta->audiocodec[sizeof(meta->audiocodec) - 1] = '\0';
}
if (strncmp(gst_tag_get_nick(tag), "video codec", 11) == 0) {
strncpy(meta->videocodec, str, sizeof(meta->videocodec));
meta->videocodec[sizeof(meta->videocodec) - 1] = '\0';
}
#endif
}
}
#ifdef GET_STREAM_INFO_FROM_TAGS
else if (G_VALUE_HOLDS_UINT (val)) {
guint value = g_value_get_uint (val);
if (strncmp(gst_tag_get_nick(tag), "bitrate", 7) == 0) {
meta->audiobitrate = value;
}
if (strncmp(gst_tag_get_nick(tag), "image width", 11) == 0) {
meta->width = value;
}
if (strncmp(gst_tag_get_nick(tag), "image height", 12) == 0) {
meta->height = value;
}
if (strncmp(gst_tag_get_nick(tag), "frame rate", 10) == 0) {
meta->framerate = value;
}
if (strncmp(gst_tag_get_nick(tag), "video bitrate", 13) == 0) {
meta->videobitrate = value;
}
if (strncmp(gst_tag_get_nick(tag), "number of channels", 18) == 0) {
meta->channels = value;
}
if (strncmp(gst_tag_get_nick(tag), "sampling frequency (Hz)", 23) == 0) {
meta->samplerate = value;
}
}
#endif
else {
continue;
}
}
}
/* Extract some metadata from the streams and print it on the screen */
static void analyze_streams (gpointer data)
{
gint i;
GstTagList *tags;
GstCaps *caps;
GstStructure *st;
GstPad *pad;
gchar *str;
gint ntracks = 0;
play_engine *engine = (play_engine *)data;
/* Read some properties */
g_object_get (engine->bin, "n-video", &engine->meta.n_video, NULL);
g_object_get (engine->bin, "n-audio", &engine->meta.n_audio, NULL);
g_object_get (engine->bin, "n-text", &engine->meta.n_subtitle, NULL);
ntracks = engine->meta.n_video;
if (ntracks > MAX_VIDEO_TRACK_COUNT)
ntracks = MAX_VIDEO_TRACK_COUNT;
for (i = 0; i < ntracks; i++) {
tags = NULL;
pad = NULL;
/* Retrieve the stream's video tags */
g_signal_emit_by_name (engine->bin, "get-video-pad", i, &pad);
if (pad) {
caps = gst_pad_get_current_caps (pad);
st = gst_caps_get_structure (caps, 0);
gst_structure_get_int (st, "width", &engine->meta.video_info[i].width);
gst_structure_get_int (st, "height", &engine->meta.video_info[i].height);
gst_structure_get_fraction (st, "framerate",
&engine->meta.video_info[i].framerate_numerator,
&engine->meta.video_info[i].framerate_denominator);
gst_caps_unref (caps);
gst_object_unref (pad);
}
g_signal_emit_by_name (engine->bin, "get-video-tags", i, &tags);
if (tags) {
str = NULL;
gst_tag_list_get_string (tags, GST_TAG_VIDEO_CODEC, &str);
strncpy (engine->meta.video_info[i].codec_type, str ? str : "unknown",
METADATA_ITEM_SIZE_SMALL);
engine->meta.video_info[i].codec_type[METADATA_ITEM_SIZE_SMALL-1] = '\0';
g_free (str);
str = NULL;
gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str);
strncpy (engine->meta.video_info[i].language, str ? str : "unknown",
METADATA_ITEM_SIZE_SMALL);
engine->meta.video_info[i].language[METADATA_ITEM_SIZE_SMALL-1] = '\0';
g_free (str);
gst_tag_list_get_uint (tags, GST_TAG_BITRATE,
&engine->meta.video_info[i].bitrate);
gst_tag_list_free (tags);
}
}
ntracks = engine->meta.n_audio;
if (ntracks > MAX_AUDIO_TRACK_COUNT)
ntracks = MAX_AUDIO_TRACK_COUNT;
for (i = 0; i < ntracks; i++) {
tags = NULL;
pad = NULL;
/* Retrieve the stream's audio tags */
g_signal_emit_by_name (engine->bin, "get-audio-pad", i, &pad);
if (pad) {
caps = gst_pad_get_current_caps (pad);
st = gst_caps_get_structure (caps, 0);
gst_structure_get_int (st, "rate",
&engine->meta.audio_info[i].samplerate);
gst_structure_get_int (st, "channels",
&engine->meta.audio_info[i].channels);
gst_caps_unref (caps);
gst_object_unref (pad);
}
g_signal_emit_by_name (engine->bin, "get-audio-tags", i, &tags);
if (tags) {
str = NULL;
gst_tag_list_get_string (tags, GST_TAG_AUDIO_CODEC, &str);
strncpy (engine->meta.audio_info[i].codec_type, str ? str : "unknown",
METADATA_ITEM_SIZE_SMALL);
engine->meta.audio_info[i].codec_type[METADATA_ITEM_SIZE_SMALL-1] = '\0';
g_free (str);
str = NULL;
gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str);
strncpy(engine->meta.audio_info[i].language, str ? str : "unknown",
METADATA_ITEM_SIZE_SMALL);
engine->meta.audio_info[i].language[METADATA_ITEM_SIZE_SMALL-1] = '\0';
g_free (str);
gst_tag_list_get_uint (tags, GST_TAG_BITRATE,
&engine->meta.audio_info[i].bitrate);
gst_tag_list_free (tags);
}
}
ntracks = engine->meta.n_subtitle;
if (ntracks > MAX_SUBTITLE_TRACK_COUNT)
ntracks = MAX_SUBTITLE_TRACK_COUNT;
for (i = 0; i < ntracks; i++) {
tags = NULL;
/* Retrieve the stream's subtitle tags */
g_signal_emit_by_name (engine->bin, "get-text-tags", i, &tags);
if (tags) {
str = NULL;
gst_tag_list_get_string (tags, GST_TAG_SUBTITLE_CODEC, &str);
strncpy (engine->meta.subtitle_info[i].codec_type, str ? str : "unknown",
METADATA_ITEM_SIZE_SMALL);
engine->meta.subtitle_info[i].codec_type[METADATA_ITEM_SIZE_SMALL-1]='\0';
g_free (str);
str = NULL;
gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str);
strncpy(engine->meta.subtitle_info[i].language, str ? str : "unknown",
METADATA_ITEM_SIZE_SMALL);
engine->meta.subtitle_info[i].language[METADATA_ITEM_SIZE_SMALL-1] = '\0';
g_free (str);
gst_tag_list_free (tags);
}
}
g_object_get (engine->bin, "current-video", &engine->cur_video, NULL);
g_object_get (engine->bin, "current-audio", &engine->cur_audio, NULL);
g_object_get (engine->bin, "current-text", &engine->cur_subtitle, NULL);
#ifdef PRINT_STREAM_INFO
/* print the streams info */
g_print ("%d video stream(s), %d audio stream(s), %d text stream(s)\n",
engine->meta.n_video, engine->meta.n_audio,
engine->meta.n_subtitle);
ntracks = engine->meta.n_video;
if (ntracks > MAX_VIDEO_TRACK_COUNT)
ntracks = MAX_VIDEO_TRACK_COUNT;
for (i = 0; i < ntracks; i++) {
g_print ("\n");
g_print ("video stream %d:\n", i);
g_print (" codec: %s\n", engine->meta.video_info[i].codec_type);
g_print (" language: %s\n", engine->meta.video_info[i].language);
g_print (" resolution: %d x %d \n", engine->meta.video_info[i].width,
engine->meta.video_info[i].height);
g_print (" framerate: %d/%d\n",
engine->meta.video_info[i].framerate_numerator,
engine->meta.video_info[i].framerate_denominator);
g_print (" bitrate: %d\n", engine->meta.video_info[i].bitrate);
}
ntracks = engine->meta.n_audio;
if (ntracks > MAX_AUDIO_TRACK_COUNT)
ntracks = MAX_AUDIO_TRACK_COUNT;
for (i = 0; i < ntracks; i++) {
g_print ("\n");
g_print ("audio stream %d:\n", i);
g_print (" codec: %s\n", engine->meta.audio_info[i].codec_type);
g_print (" language: %s\n", engine->meta.audio_info[i].language);
g_print (" channels: %d\n", engine->meta.audio_info[i].channels);
g_print (" sample rate: %d\n", engine->meta.audio_info[i].samplerate);
g_print (" bitrate: %d\n", engine->meta.audio_info[i].bitrate);
}
ntracks = engine->meta.n_subtitle;
if (ntracks > MAX_SUBTITLE_TRACK_COUNT)
ntracks = MAX_SUBTITLE_TRACK_COUNT;
for (i = 0; i < ntracks; i++) {
g_print ("\n");
g_print ("subtitle stream %d:\n", i);
g_print (" codec: %s\n", engine->meta.subtitle_info[i].codec_type);
g_print (" language: %s\n", engine->meta.subtitle_info[i].language);
}
g_print ("\n");
g_print ("Currently playing video %d, audio %d and subtitle %d\n",
engine->cur_video, engine->cur_audio, engine->cur_subtitle);
#endif
}
static gboolean bus_cb(GstBus *bus, GstMessage *msg, gpointer data)
{
play_engine *engine = (play_engine *)data;
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_EOS: {
g_print("end-of-stream\n");
if (engine->eos_cb)
engine->eos_cb(engine->player);
break;
}
case GST_MESSAGE_ERROR: {
gchar *debug;
GError *err;
gst_message_parse_error(msg, &err, &debug);
g_free(debug);
g_warning("Error: %s\n", err->message);
if (engine->error_cb)
engine->error_cb(engine->player, err->message);
g_error_free(err);
break;
}
case GST_MESSAGE_TAG: {
GstTagList *tags;
gst_message_parse_tag(msg, &tags);
gst_tag_list_foreach(tags, get_metadata_tag, data);
gst_tag_list_free(tags);
break;
}
case GST_MESSAGE_STATE_CHANGED: {
GstState old_st, new_st, pending_st;
gst_message_parse_state_changed (msg, &old_st, &new_st, &pending_st);
if (GST_MESSAGE_SRC (msg) == GST_OBJECT (engine->bin)) {
if (old_st == GST_STATE_READY && new_st == GST_STATE_PAUSED) {
/* Once we are in the playing state, analyze the streams */
analyze_streams (data);
}
/* inform application state changed */
//g_print("old: %d, new: %d, pending: %d\n",old_st, new_st, pending_st);
if (engine->state_change_cb)
engine->state_change_cb(engine->player, old_st, new_st, pending_st);
}
}
break;
default:
break;
}
return TRUE;
}
static gint64 playengine_get_position(play_engine *engine)
{
gint64 cur = GST_CLOCK_TIME_NONE;
if (engine) {
if (!gst_element_query_position(engine->pipeline, GST_FORMAT_TIME, &cur))
return GST_CLOCK_TIME_NONE;
}
return cur;
}
static gint64 playengine_get_duration(play_engine *engine)
{
gint64 dur = GST_CLOCK_TIME_NONE;
if (engine) {
gst_element_query_duration(engine->pipeline, GST_FORMAT_TIME, &dur);
engine->duration = dur;
}
return dur;
}
static void playengine_set_file(play_engine *engine, gchar *filename)
{
gchar uri[256] = {0};
if (engine && filename) {
if (strstr(filename, "://")) {
snprintf(uri, 255, "%s", filename);
} else if( filename[0] == '/' ) {
snprintf(uri, 255, "file://%s", filename);
} else {
gchar* pwd = getenv("PWD");
snprintf(uri, 255, "file://%s/%s", pwd, filename);
}
g_object_set(G_OBJECT(engine->bin), "uri", uri, NULL);
}
}
static void playengine_play(play_engine *engine)
{
if (engine) {
gst_element_set_state(engine->pipeline, GST_STATE_PLAYING);
engine->play_rate = 1.0;
}
}
static void playengine_stop(play_engine *engine)
{
if (engine)
gst_element_set_state(engine->pipeline, GST_STATE_NULL);
}
static void playengine_pause(play_engine *engine)
{
if (engine)
gst_element_set_state(engine->pipeline, GST_STATE_PAUSED);
}
static void playengine_seek(play_engine *engine, gint64 value,
gboolean accurate)
{
GstEvent *seek = NULL;
GstSeekFlags flag = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT;
if (engine) {
engine->duration = playengine_get_duration(engine);
if (accurate)
flag |= GST_SEEK_FLAG_ACCURATE;
seek = gst_event_new_seek(1.0, GST_FORMAT_TIME, flag, GST_SEEK_TYPE_SET,
value, GST_SEEK_TYPE_SET, engine->duration);
gst_element_send_event(engine->pipeline, seek);
engine->play_rate = 1.0;
}
}
static void playengine_set_play_rate(play_engine *engine, double rate)
{
GstEvent *set_playback_rate_event = NULL;
gint64 cur;
GstQuery* query;
if(rate > 16.0 || rate < -16.0) {
g_print("Invalid rate=%f, should be between [-16.0, 16.0]!\n", rate);
return;
}
query = gst_query_new_position(GST_FORMAT_TIME);
if( gst_element_query(engine->bin, query) ) {
gst_query_parse_position(query,NULL,&cur);
//g_print("current_position = %"GST_TIME_FORMAT"\n", GST_TIME_ARGS (cur));
} else {
g_print ("current_postion query failed...\n");
}
gst_element_query_duration(engine->bin, GST_FORMAT_TIME, &(engine->duration));
if( rate >= 0.0 ) {
set_playback_rate_event = gst_event_new_seek(rate, GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
GST_SEEK_TYPE_SET, cur, GST_SEEK_TYPE_SET, engine->duration);
} else {
set_playback_rate_event = gst_event_new_seek(rate, GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, cur);
}
if(gst_element_send_event(engine->bin, set_playback_rate_event) == FALSE) {
g_print("Send setting playback rate event failed!\n");
if (engine->error_cb)
engine->error_cb(engine->player,
"Send setting playback rate event failed!");
return;
}
engine->play_rate = rate;
}
static double playengine_get_play_rate(play_engine *engine)
{
return engine->play_rate;
}
static void playengine_set_rotate(play_engine *engine, gint rotation)
{
g_object_set(G_OBJECT(engine->video_sink), "rotate", rotation, NULL);
g_object_set(G_OBJECT(engine->video_sink), "reconfig", 1, NULL);
}
static PlayEngineState playengine_get_state(play_engine *engine)
{
PlayEngineState state = PLAYENGINE_UNKNOWN;
GstState gst_state = GST_STATE_VOID_PENDING;
if (engine) {
gst_element_get_state(engine->pipeline, &gst_state, NULL, GST_SECOND);
if (GST_STATE_NULL == gst_state || GST_STATE_READY == gst_state)
state = PLAYENGINE_STOPPED;
else if (GST_STATE_PAUSED == gst_state)
state = PLAYENGINE_PAUSED;
else if (GST_STATE_PLAYING == gst_state)
state = PLAYENGINE_PLAYING;
}
return state;
}
static void playengine_set_force_ratio (play_engine *engine, gboolean force)
{
if (engine)
g_object_set(G_OBJECT(engine->bin), "force-aspect-ratio", force, NULL);
}
static void playengine_get_metadata(play_engine *engine, imx_metadata *meta)
{
if (engine && meta)
memcpy(meta, &engine->meta, sizeof (imx_metadata));
}
static gint playengine_get_subtitle_num(play_engine *engine)
{
if (engine && engine->meta.n_subtitle == 0)
g_object_get (G_OBJECT(engine->bin), "n-text",
&engine->meta.n_subtitle, NULL);
return engine->meta.n_subtitle;
}
static gint playengine_get_audio_num(play_engine *engine)
{
if (engine && engine->meta.n_audio == 0)
g_object_get (G_OBJECT(engine->bin), "n-audio",
&engine->meta.n_audio, NULL);
return engine->meta.n_audio;
}
static gint playengine_get_video_num(play_engine *engine)
{
if (engine && engine->meta.n_video == 0)
g_object_get (G_OBJECT(engine->bin), "n-video",
&engine->meta.n_video, NULL);
return engine->meta.n_video;
}
static gint playengine_get_current_audio_no(play_engine *engine)
{
return engine->cur_audio;
}
static gint playengine_get_current_video_no(play_engine *engine)
{
return engine->cur_video;
}
static gint playengine_get_current_subtitle_no(play_engine *engine)
{
return engine->cur_subtitle;
}
static void playengine_select_subtitle(play_engine *engine, gint text_no)
{
if (engine && text_no != engine->cur_subtitle) {
if (text_no < engine->meta.n_subtitle) {
g_object_set( engine->bin, "current-text", text_no, NULL );
g_object_get (engine->bin, "current-text", &engine->cur_subtitle, NULL);
} else {
g_print("subtitle number out of range %d, %d\n", text_no,
engine->meta.n_subtitle);
}
}
}
static void playengine_select_audio(play_engine *engine, gint audio_no)
{
if (engine && audio_no != engine->cur_audio) {
if (audio_no < engine->meta.n_audio) {
g_object_set( engine->bin, "current-audio", audio_no, NULL );
g_object_get( engine->bin, "current-audio", &engine->cur_audio, NULL );
} else {
g_print("audio number out of range %d, %d\n", audio_no,
engine->meta.n_audio);
}
}
}
static void playengine_select_video(play_engine *engine, gint video_no)
{
if (engine && video_no != engine->cur_video) {
if (video_no < engine->meta.n_video) {
g_object_set( engine->bin, "current-video", video_no, NULL );
g_object_get( engine->bin, "current-video", &engine->cur_video, NULL );
} else {
g_print("video number out of range %d, %d\n", video_no,
engine->meta.n_video);
}
}
}
static gboolean playengine_get_subtitle_text(play_engine *engine, gchar *text)
{
//TODO text-sink??
return 1;
}
static void playengine_set_volume(play_engine *engine, gdouble volume)
{
GValue value = {0};
if (engine) {
if( volume >= 0.0 && volume <= 1.0 ) {
g_value_init(&value, G_TYPE_DOUBLE);
g_value_set_double(&value, volume);
g_object_set_property(G_OBJECT(engine->bin), "volume", &value);
} else {
g_print("Volume out of range %f\n", volume);
}
}
}
static gdouble playengine_get_volume(play_engine *engine)
{
GValue value = {0};
g_value_init(&value, G_TYPE_DOUBLE);
if (engine)
g_object_get_property(G_OBJECT(engine->bin), "volume", &value);
return g_value_get_double(&value);
}
static void playengine_set_mute(play_engine *engine, gboolean mute)
{
GValue value = {0};
if (engine) {
g_value_init(&value, G_TYPE_BOOLEAN);
g_value_set_boolean(&value, mute);
g_object_set_property(G_OBJECT(engine->bin), "mute", &value);
}
}
static gboolean playengine_get_seekable(play_engine *engine)
{
GstQuery *query;
gboolean res;
gboolean seekable = FALSE;
if (engine) {
query = gst_query_new_seeking (GST_FORMAT_TIME);
if (gst_element_query (engine->bin, query)) {
gst_query_parse_seeking (query, NULL, &res, NULL, NULL);
if (res)
seekable = TRUE;
}
gst_query_unref (query);
}
return seekable;
}
static void playengine_set_window(play_engine *engine, guintptr handle)
{
if (engine) {
#ifndef PREPARE_WINDOW_MESSAGE
if (GST_IS_VIDEO_OVERLAY (engine->video_sink)) {
g_print("videosink is overlay\n");
gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(engine->video_sink),
handle);
} else {
g_print("videosink is not overlay\n");
}
#else
engine->video_window_handle = handle;
#endif
}
}
static void playengine_set_render_rect(play_engine *engine,
gint x, gint y, gint w, gint h)
{
if (engine && GST_IS_VIDEO_OVERLAY(engine->video_sink)) {
gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(engine->video_sink)
,x, y, w, h);
}
}
static void playengine_expose_video(play_engine *engine)
{
if (engine && GST_IS_VIDEO_OVERLAY(engine->video_sink))
gst_video_overlay_expose(GST_VIDEO_OVERLAY(engine->video_sink));
}
play_engine * play_engine_create(int *argc, char **argv[],
void (*eos_cb)(void *),
void (*error_cb)(void *, const gchar *),
void (*state_change_cb)(void *, GstState, GstState, GstState))
{
play_engine *engine = NULL;
guint major, minor, micro, nano;
engine = (play_engine *)malloc(sizeof(play_engine));
if (!engine) {
g_print("malloc play engine failed\n");
return NULL;
} else {
memset (engine, 0, sizeof (play_engine));
}
gst_init(argc, argv);
gst_version (&major, &minor, &micro, &nano);
g_print ("GStreamer version %d.%d.%d\n", major, minor, micro);
engine->pipeline = gst_pipeline_new("gst-player");
engine->bin = gst_element_factory_make("playbin", "bin");
#ifdef VIDEO_SINK_V4L2SINK
engine->video_sink = gst_element_factory_make ("imxv4l2sink", "videosink");
#else
engine->video_sink = gst_element_factory_make ("overlaysink", "videosink");
#endif
g_object_set(G_OBJECT(engine->bin), "video-sink", engine->video_sink, NULL);
gst_bin_add(GST_BIN(engine->pipeline), engine->bin);
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(engine->pipeline));
gst_bus_add_watch(bus, bus_cb, engine);
#ifdef PREPARE_WINDOW_MESSAGE
gst_bus_set_sync_handler(bus, (GstBusSyncHandler)bus_sync_cb, engine, NULL);
#endif
gst_object_unref(bus);
engine->set_file = playengine_set_file;
engine->play = playengine_play;
engine->stop = playengine_stop;
engine->pause = playengine_pause;
engine->seek = playengine_seek;
engine->set_play_rate = playengine_set_play_rate;
engine->get_play_rate = playengine_get_play_rate;
engine->rotate = playengine_set_rotate;
engine->force_ratio = playengine_set_force_ratio;
engine->get_state = playengine_get_state;
engine->get_position = playengine_get_position;
engine->get_duration = playengine_get_duration;
engine->get_metadata = playengine_get_metadata;
engine->get_subtitle_num = playengine_get_subtitle_num;
engine->get_audio_num = playengine_get_audio_num;
engine->get_video_num = playengine_get_video_num;
engine->get_cur_subtitle_no = playengine_get_current_subtitle_no;
engine->get_cur_audio_no = playengine_get_current_audio_no;
engine->get_cur_video_no = playengine_get_current_video_no;
engine->set_volume = playengine_set_volume;
engine->get_volume = playengine_get_volume;
engine->set_mute = playengine_set_mute;
engine->get_seekable = playengine_get_seekable;
engine->set_window = playengine_set_window;
engine->set_render_rect = playengine_set_render_rect;
engine->expose_video = playengine_expose_video;
engine->select_audio = playengine_select_audio;
engine->select_video = playengine_select_video;
engine->select_subtitle = playengine_select_subtitle;
engine->get_subtitle_text = playengine_get_subtitle_text;
engine->eos_cb = eos_cb;
engine->error_cb = error_cb;
engine->state_change_cb = state_change_cb;
return engine;
}
void play_engine_destroy(play_engine *engine)
{
if (engine) {
gst_element_set_state(engine->pipeline, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(engine->pipeline));
free(engine);
}
}