# HG changeset patch # User hgs # Date 1277504326 18000 # Node ID 8d4f92b9230e4eeed2bdb459f2c8c6ee76e3b30f # Parent 5cb7d96a68874a62cb8060d0ab4906ef16ce1594 201025 diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/QtGSTPlayer.pro --- a/QtGSTPlayer/QtGSTPlayer.pro Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -###################################################################### -# Automatically generated by qmake (2.01a) Wed Feb 17 14:34:47 2010 -###################################################################### - - -# ============================================================================ -# Name : QtGSTPlayer.pro -# Part of : LibHb / gstplayer -# Description : Project definition file for simple gstplayer -# Version : %version: 1 % -# -# Copyright ? 2008 Nokia. All rights reserved. -# This material, including documentation and any related computer -# programs, is protected by copyright controlled by Nokia. All -# rights are reserved. Copying, including reproducing, storing, -# adapting or translating, any or all of this material requires the -# prior written consent of Nokia. This material also contains -# confidential information which may not be disclosed to others -# without the prior written consent of Nokia. -# ============================================================================ -# - -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += main.cpp folderview.cpp views.cpp record_play.c -HEADERS += folderview.h views.h - -RESOURCES += QtGSTPlayer.qrc - diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/QtGSTPlayer.qrc --- a/QtGSTPlayer/QtGSTPlayer.qrc Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ - - - folder.png - settings.png - - diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/folder.png Binary file QtGSTPlayer/folder.png has changed diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/folderview.cpp --- a/QtGSTPlayer/folderview.cpp Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,357 +0,0 @@ -#include -#include -#include - -//#include -//#include -#include -#include -#include -#include - -#include -#include -#include -#include "folderview.h" -#include "views.h" -#include -#include -#include -/*! Constructor of FolderView. - */ -#ifdef __cplusplus -extern "C" -{ -#endif - -int mCurrentState = 0; - -#ifdef __cplusplus -} -#endif -//extern int mCurrentState; - -FolderView::FolderView(QGraphicsItem *parent) - : HbView(parent),mModel( NULL ), mFolderPath("c:\\data\\Sounds\\Digital\\"),mTimer(NULL),mIsRecording( FALSE ) -{ - mCurrentState = NONE; - - // Create a main widget for this view - // In this case, list view is appropriate - // Note: HbListView is not derived from HbView, - // this is just like any other Hb widget but with a feature of - // model-view separation - mFileList = new HbListView(this); - - // Create a model to set for the list view - mModel = new QDirModel(this); - mFileList->setModel(mModel); - - // Setting initial path for folder list - mFileList->setRootIndex(mModel->index(mFolderPath)); - //mFileList-> - // Setting the main widget for this view - setWidget(mFileList); - //int x = mFileList->indexCount(); - QObject::connect(mFileList, SIGNAL(pressed(const QModelIndex)), this, SLOT(item_pressed(const QModelIndex))); - - // add menu - HbMenu* menu1 = menu()->addMenu(tr("Record")); - - HbAction* menu1_Action = new HbAction(tr("RAW"), this); - connect(menu1_Action, SIGNAL(triggered()), this, SLOT(record_RAW())); - menu1->addAction( menu1_Action ); - - menu1_Action = new HbAction(tr("WAV"), this); - connect(menu1_Action, SIGNAL(triggered()), this, SLOT(record_WAV())); - menu1->addAction( menu1_Action ); - - //create action Nokia India sub menu item. - menu1_Action = new HbAction(tr("AMR"), this); - connect(menu1_Action, SIGNAL(triggered()), this, SLOT(record_AMR())); - menu1->addAction( menu1_Action ); - - menu1_Action = new HbAction(tr("G711"), this); - connect(menu1_Action, SIGNAL(triggered()), this, SLOT(record_G711())); - menu1->addAction( menu1_Action ); - - menu1_Action = new HbAction(tr("AAC"), this); - connect(menu1_Action, SIGNAL(triggered()), this, SLOT(record_AAC())); - menu1->addAction( menu1_Action ); - menu1_Action = new HbAction(tr("G729"), this); - connect(menu1_Action, SIGNAL(triggered()), this, SLOT(record_G729())); - menu1->addAction( menu1_Action ); - - menu1_Action = new HbAction(tr("ILBC"), this); - connect(menu1_Action, SIGNAL(triggered()), this, SLOT(record_ILBC())); - menu1->addAction( menu1_Action ); - - - - //menu()->addAction(tr("Play"), this, SLOT(play())); - menu()->addAction(tr("Stop"), this, SLOT(stop())); - menu()->addAction(tr("Pause"), this, SLOT(pause())); - menu()->addAction(tr("Resume"), this, SLOT(resume())); - menu()->addAction(tr("Exit"), qApp, SLOT(quit())); - - - /// timer required to get the glib events - mTimer = new QTimer(this); - connect(mTimer, SIGNAL(timeout()), this, SLOT(timertimeout())); - mTimer->start(10); - -} - -FolderView::~FolderView() -{ - if(mCurrentState != NONE) - gst_unref(); -delete mFileList; -delete mModel; -mTimer->stop(); -delete mTimer; -} - - -void FolderView::folderViewTriggered() -{ - mainWindow()->setCurrentView(Views::folderView()); -} - -/*void FolderView::settingsViewTriggered() -{ - mainWindow()->setCurrentView(Views::settingsView()); -}*/ - -void FolderView::showNote(const int err) -{ - if(err) - { - HbNotificationDialog* notifyDialog = new HbNotificationDialog; - notifyDialog->setTimeout(HbPopup::StandardTimeout); - QString strong; - QString sprint= strong.sprintf("Format Not supported(%d)",err); - notifyDialog->setTitleTextWrapping(Hb::TextWordWrap); - notifyDialog->setTitle(QString("Error")); - notifyDialog->setWrapMode(Hb::TextWordWrap); - notifyDialog->setText(sprint); - - notifyDialog->exec(); - delete notifyDialog; - } -} -void FolderView::item_pressed(const QModelIndex &index) -{ - if( mIsRecording ) - { - return; - } - QVariant variant=index.data(); - QString str = variant.toString(); - - - QString fullpath = mFolderPath; - fullpath.append( str ); - - TBuf16<1024> buf16; - buf16.Copy( (TUint16*)fullpath.data_ptr()->data ,fullpath.data_ptr()->size ); - TBuf8<1024> buf8; - buf8.Copy( buf16 ); - - if( NONE != mCurrentState ) - { - gst_unref(); - } - - int err = gst_play_file( (char*)buf8.PtrZ() ); - if(err) - { - showNote(err); - mCurrentState = NONE; - } - else - { - mCurrentState = PLAYING; - } - -} -void FolderView::pause() -{ - if( PLAYING == mCurrentState ){ - gst_pause(); - mCurrentState = PAUSE; - } -} - -void FolderView::resume() -{ - if( PAUSE == mCurrentState ){ - gst_resume(); - mCurrentState = PLAYING; - } -} - -void FolderView::stop() -{ - if( mIsRecording == TRUE ) - { - gst_record_stop(); - - if( mModel ) - delete mModel; - - mModel = new QDirModel(this); - mFileList->setModel(mModel); - - mFileList->reset(); - mFileList->setRootIndex(mModel->index(mFolderPath)); -// mFileList->show(); -// int x = mFileList->indexCount(); - //setWidget(mFileList); - mIsRecording = FALSE; - return; - } - if( PLAYING == mCurrentState || PAUSE == mCurrentState ){ - gst_unref(); - mCurrentState = NONE; - } -} - -void FolderView::record_AMR() -{ - if( mCurrentState == NONE ){ - int err = gst_record_file( RECORD_AMR ); - if(err) - { - showNote(err); - mCurrentState = NONE; - mIsRecording = FALSE; - } - else - { - mCurrentState = PLAYING; - mIsRecording = TRUE; - } - } -} - -void FolderView::record_WAV() -{ - if( mCurrentState == NONE ){ - int err = gst_record_file( RECORD_WAV ); - if(err) - { - showNote(err); - mCurrentState = NONE; - mIsRecording = FALSE; - } - else - { - mCurrentState = PLAYING; - mIsRecording = TRUE; - } - //gst_record_wav(); - } -} - -void FolderView::record_RAW() -{ - if( mCurrentState == NONE ){ - int err = gst_record_file( RECORD_RAW ); - if(err) - { - showNote(err); - mCurrentState = NONE; - mIsRecording = FALSE; - } - else - { - mCurrentState = PLAYING; - mIsRecording = TRUE; - } - } -} - -void FolderView::record_G711() -{ - if( mCurrentState == NONE ){ - int err = gst_record_file( RECORD_G711 ); - if(err) - { - showNote(err); - mCurrentState = NONE; - mIsRecording = FALSE; - } - else - { - mCurrentState = PLAYING; - mIsRecording = TRUE; - } - } -} - -void FolderView::record_G729() -{ - if( mCurrentState == NONE ){ - int err = gst_record_file( RECORD_G729 ); - if(err) - { - showNote(err); - mCurrentState = NONE; - mIsRecording = FALSE; - } - else - { - mCurrentState = PLAYING; - mIsRecording = TRUE; - } - } -} - -void FolderView::record_ILBC() -{ - if( mCurrentState == NONE ){ - int err = gst_record_file( RECORD_ILBC ); - if(err) - { - showNote(err); - mCurrentState = NONE; - mIsRecording = FALSE; - } - else - { - mCurrentState = PLAYING; - mIsRecording = TRUE; - } - } -} - -void FolderView::record_AAC() -{ - if( mCurrentState == NONE ){ - int err = gst_record_file( RECORD_AAC ); - if(err) - { - showNote(err); - mCurrentState = NONE; - mIsRecording = FALSE; - } - else - { - mCurrentState = PLAYING; - mIsRecording = TRUE; - } - } -} -void FolderView::timertimeout() -{ - if( PLAYING == mCurrentState ){ - gst_get_events(); - } - - if( STOP == mCurrentState ){ - gst_unref(); - mCurrentState = NONE; - mIsRecording = FALSE; - } -} diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/folderview.h --- a/QtGSTPlayer/folderview.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -#ifndef FOLDERVIEW_H -#define FOLDERVIEW_H - -#include -//#include - -#include "record_play.h" - -QT_BEGIN_NAMESPACE -class QDirModel; -QT_END_NAMESPACE - -//class HbFormItem; -class HbListView; - -class FolderView : public HbView -{ - Q_OBJECT - -public: - explicit FolderView(QGraphicsItem *parent = 0); - ~FolderView(); -public slots: - void folderViewTriggered(); - //void settingsViewTriggered(); - void item_pressed(const QModelIndex &index); -// - void record_AMR(); - void record_WAV(); - void record_RAW(); - void record_G711(); - void record_G729(); - void record_ILBC(); - void record_AAC(); - - void pause(); - void resume(); - void stop(); - void timertimeout(); - void showNote(const int err); - -//void record_file( int type ); - - -private: - HbListView *mFileList; - -//signals: -// void pressed(const QModelIndex &index); -// void released(const QModelIndex &index); -// void activated(const QModelIndex &index); -// void longPressed(HbAbstractViewItem *item, const QPointF &coords); - - QDirModel *mModel; - QString mFolderPath; - QTimer *mTimer; - bool mIsRecording; - - - //state st; - -}; - -#endif // FOLDERVIEW_H diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/main.cpp --- a/QtGSTPlayer/main.cpp Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/*! This is an example application demonstrating how a simple Hb - application is created. This application implements a folder - browser. The application creates two views. The main view (Folder - view) shows the folder contents. The second view (Settings view) can - be used to set the path which is shown in the Folder view. Settings - view uses the HbFormView. Folder view inherits HbView and implements - a couple of methods to populate the Folder view. */ - -#include -#include -#include -#include -#include - - -#include -#include -#include - -#include "folderview.h" -#include "views.h" - -int main(int argc, char *argv[]) -{ - // Create HbApplication - gst_init (&argc, &argv); - HbApplication a(argc, argv); - a.setApplicationName(QObject::tr("Folder Browser")); - //LOG(_L("Entering main.cpp")); - - // Create main window - HbMainWindow mainWindow; - - // Create View#1 : Folder view - HbView *folderView = new FolderView; - // Title pane text - folderView->setTitle(QObject::tr("QtGSTPlayer")); - - // Add two views to main window, - // the adding order determines which one is shown first - - mainWindow.addView(folderView); - /*mainWindow.addView(settingsView);*/ - - // Store the mainwindow ptr. - Views::win = &mainWindow; - - // Show main window - mainWindow.show(); - - return a.exec(); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/record_play.c --- a/QtGSTPlayer/record_play.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,855 +0,0 @@ - - -#include -#include -#include -#include "record_play.h" - - -GstElement *bin; -extern int mCurrentState; - -static GstElement * -create_video_output () -{ - static gboolean have_video = FALSE; - GstBin *bin; - GstElement *queue, *sink; - GstPad *pad; - - if (have_video) { - //g_print ("Already playing a video stream. Ignoring this one\n"); - return NULL; - } - - /* create a new bin to hold the elements */ - if((bin = (GstBin*) gst_bin_new (NULL)) == NULL) - //bin = (GstBin*) gst_pipeline_new("pipeline"); - return NULL; - - /* Queue to ensure all streams can push data */ - queue = gst_element_factory_make ("queue", "q"); - if(queue == NULL) - return NULL;/* Queue should always be available */ - /* Set the queue to buffer 1/10 of a second of raw video */ - g_object_set (queue, "max-size-time", (GstClockTime) GST_SECOND / 10, - "max-size-bytes", 0, "max-size-buffers", 0, NULL); - -// cs = gst_element_factory_make ("ffmpegcolorspace", "cs"); -// if (!cs) -// goto no_output; - - /* and a video sink */ - sink = gst_element_factory_make ("fakesink"/*autovideosink*/, "sink"); - if (!sink) - goto no_output; - - /* add objects to the main pipeline */ - gst_bin_add_many (GST_BIN (bin), queue, sink, NULL); - - /* Link the elements */ - gst_element_link_many (queue, sink, NULL); - - /* Retrieve the sinkpad from the queue and 'ghost' it onto - * the bin so that the caller can find it generically */ - pad = gst_element_get_pad (queue, "sink"); - gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad)); - gst_object_unref (pad); - - //have_video = TRUE; - - return GST_ELEMENT (bin); - - /* ERRORS */ -no_output: - { - //g_print ("Could not create either ffmpegcolorspace or autovideosink for output"); - return NULL; - } -} - -static GstElement * -create_audio_output () -{ - static gboolean have_audio = FALSE; - GstBin *bin; - GstElement *queue, *audioconvert,*audioresample, *sink; - GstPad *pad; - - if (have_audio) { - //g_print ("Already playing an audio stream. Ignoring this one\n"); - return NULL; - } - - /* create a new bin to hold the elements */ - bin = (GstBin*) gst_bin_new (NULL); - if(!bin) - goto no_output; - - /* Queue to ensure all streams can push data */ - queue = gst_element_factory_make ("queue", "q"); - if (!queue) /* Queue should always be available */ - goto no_output; - /* Set the queue to buffer 1/10 of a second of raw audio */ - g_object_set (queue, "max-size-time", (GstClockTime) GST_SECOND / 10, - "max-size-bytes", 0, "max-size-buffers", 0, NULL); - - /* an audio converter to convert floating-point audio samples to int format */ - audioconvert = gst_element_factory_make ("audioconvert", "ac"); - if (!audioconvert) - goto no_output; - - /* an audio converter to convert floating-point audio samples to int format */ - audioresample = gst_element_factory_make ("audioresample", "audioresample"); - if (!audioresample) - goto no_output; - - /* and an audio sink */ - sink = gst_element_factory_make ("autoaudiosink", "sink"); - if (!sink) - goto no_output; - - /* add objects to the bin */ - gst_bin_add_many (GST_BIN (bin), queue, audioconvert,audioresample, sink, NULL); - - /* link the elements */ - gst_element_link_many (queue, audioconvert,audioresample, sink, NULL); - - /* Retrieve the sinkpad from the queue element and 'ghost' it onto - * the bin so that the caller can find it generically */ - pad = gst_element_get_pad (queue, "sink"); - gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad)); - gst_object_unref (pad); - - //have_audio = TRUE; - - return GST_ELEMENT (bin); - - /* ERRORS */ -no_output: - { - //g_print ("Could not create either ffmpegcolorspace or autovideosink for output"); - return NULL; - } -} - -static void -new_decoded_pad (GstElement * element, GstPad * pad, gboolean last, - GstBin *top_pipeline) -{ - GstPad *out_pad; - GstElement *output = NULL; - GstCaps *caps; - GstStructure *s; - const gchar *stream_type; - - /* Decide which output we are creating based on the stream contents */ - caps = gst_pad_get_caps (pad); - if (caps == NULL) { - //g_print ("Decodebin produced an unknown stream - ignoring\n"); - return; - } - - s = gst_caps_get_structure (caps, 0); - if(s == NULL)/* Caps on a pad should always have exactly one entry */ - return; - - stream_type = gst_structure_get_name (s); - - if (g_str_has_prefix (stream_type, "video/x-raw-")) { - /* Is a new video stream */ - //g_print ("Encountered a new video stream\n"); - output = create_video_output (); - } - else if (g_str_has_prefix (stream_type, "audio/x-raw-")) { - //g_print ("Encountered a new audio stream\n"); - output = create_audio_output (); - } - else { - //g_print ("Found unknown stream of type %s - ignoring\n", stream_type); - } - - /* If no renderer was created, ignore this stream */ - if (output == NULL) - return; - - /* Add the output into our pipeline */ - gst_bin_add (top_pipeline, output); - - /* If we created a output pipeline, retrieve the sink pad from it */ - out_pad = gst_element_get_pad (output, "sink"); - g_return_if_fail (out_pad != NULL); - - /* Attempt to link the new pad to the output */ - if (gst_pad_link (pad, out_pad) != GST_PAD_LINK_OK) { - //g_print ("Failed to add the rendering pipeline for this new data stream\n"); - gst_bin_remove (top_pipeline, output); - gst_object_unref (out_pad); - return; - } - gst_object_unref (out_pad); - - /* New output renderer is successfully linked in the pipeline. - * Change its state to playing so it is ready to receive data */ - gst_element_set_state (output, GST_STATE_PLAYING); -} - -static void -print_tag (const GstTagList * list, const gchar * tag, gpointer unused) -{ - gint i, count; - - count = gst_tag_list_get_tag_size (list, tag); - - for (i = 0; i < count; i++) { - gchar *str; - - if (gst_tag_get_type (tag) == G_TYPE_STRING) { - if (!gst_tag_list_get_string_index (list, tag, i, &str)) - g_assert_not_reached (); - } else { - str = - g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i)); - } - - if (i == 0) { - //g_print (" %15s: %s\n", gst_tag_get_nick (tag), str); - } else { - //g_print (" : %s\n", str); - } - - g_free (str); - } -} - - - -static gboolean -bus_call (GstBus *bus, - GstMessage *message, - gpointer data) -{ - switch (GST_MESSAGE_TYPE (message)){ - case GST_MESSAGE_EOS: - gst_message_unref (message); - gst_element_set_state (bin, GST_STATE_NULL); - /* Unreffing the bin will clean up all its children too */ - gst_object_unref (bin); - mCurrentState = NONE; - break; - case GST_MESSAGE_ERROR:{ - GError *gerror; - gchar *debug; - - gst_message_parse_error (message, &gerror, &debug); - gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); - gst_message_unref (message); - g_error_free (gerror); - g_free (debug); - gst_element_set_state (bin, GST_STATE_NULL); - /* Unreffing the bin will clean up all its children too */ - gst_object_unref (bin); - mCurrentState = NONE; - break; - } - case GST_MESSAGE_WARNING:{ - GError *gerror; - gchar *debug; - - gst_message_parse_warning (message, &gerror, &debug); - gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); - gst_message_unref (message); - g_error_free (gerror); - g_free (debug); - break; - } - case GST_MESSAGE_TAG: - { - GstTagList *tags; - - gst_message_parse_tag (message, &tags); - if (tags) { - //g_print ("TAGS received from element \"%s\".\n", - // GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)))); - - gst_tag_list_foreach (tags, print_tag, NULL); - gst_tag_list_free (tags); - tags = NULL; - } - break; - } - default: - gst_message_unref (message); - break; - } - return TRUE; -} - - - -//static void -//event_loop (GstElement * pipe) -//{ -// GstBus *bus; -// GstMessage *message = NULL; -// -// bus = gst_element_get_bus (GST_ELEMENT (pipe)); -// -// while (TRUE) { -// message = gst_bus_poll (bus, GST_MESSAGE_ANY, -1); -// -// g_assert (message != NULL); -// -// switch (message->type) { -// case GST_MESSAGE_EOS: -// gst_message_unref (message); -// return; -// case GST_MESSAGE_ERROR:{ -// GError *gerror; -// gchar *debug; -// -// gst_message_parse_error (message, &gerror, &debug); -// gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); -// gst_message_unref (message); -// g_error_free (gerror); -// g_free (debug); -// return; -// } -// case GST_MESSAGE_WARNING:{ -// GError *gerror; -// gchar *debug; -// -// gst_message_parse_warning (message, &gerror, &debug); -// gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); -// gst_message_unref (message); -// g_error_free (gerror); -// g_free (debug); -// break; -// } -// case GST_MESSAGE_TAG: -// { -// GstTagList *tags; -// -// gst_message_parse_tag (message, &tags); -// if (tags) { -// //g_print ("TAGS received from element \"%s\".\n", -// GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)))); -// -// gst_tag_list_foreach (tags, print_tag, NULL); -// gst_tag_list_free (tags); -// tags = NULL; -// } -// break; -// } -// default: -// gst_message_unref (message); -// break; -// } -// } -//} - -int -gst_play_file (const char* file) -{ - GstElement *filesrc, *decodebin, *sink; - GstCaps* caps; - //int length = strlen( file ); - //gst_init (&argc, &argv); - - if (file == NULL) { - //g_print ("file is not present"); - goto no_output; - } - - //g_print ("Constructing pipeline\n"); - - /* create a new bin to hold the elements */ - bin = gst_pipeline_new ("pipeline"); - if(!bin) - goto no_output; - - /* create a disk reader */ - filesrc = gst_element_factory_make ("filesrc", "disk_source"); - if(!filesrc) - goto no_output; - - g_object_set (G_OBJECT (filesrc), "location", file, NULL); - - if( g_str_has_suffix (file, "raw") ) - { - sink = gst_element_factory_make ("devsoundsink", "sink"); - caps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - gst_bin_add_many (GST_BIN (bin), filesrc, sink, NULL); - - gst_element_link_filtered (filesrc, sink, caps); - } - else if( g_str_has_suffix (file, "g711") ) - { - sink = gst_element_factory_make ("devsoundsink", "sink"); - caps = gst_caps_new_simple ("audio/x-alaw", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - gst_bin_add_many (GST_BIN (bin), filesrc, sink, NULL); - - gst_element_link_filtered (filesrc, sink, caps); - } - else if( g_str_has_suffix (file, "g729") ) - { - sink = gst_element_factory_make ("devsoundsink", "sink"); - caps = gst_caps_new_simple ("audio/g729", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - gst_bin_add_many (GST_BIN (bin), filesrc, sink, NULL); - - gst_element_link_filtered (filesrc, sink, caps); - } - else if( g_str_has_suffix (file, "ilbc") ) - { - sink = gst_element_factory_make ("devsoundsink", "sink"); - - caps = gst_caps_new_simple ("audio/ilbc", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - gst_bin_add_many (GST_BIN (bin), filesrc, sink, NULL); - - gst_element_link_filtered (filesrc, sink, caps); - } - else if( g_str_has_suffix (file, "amr") ) - { - sink = gst_element_factory_make ("devsoundsink", "sink"); - caps = gst_caps_new_simple ("audio/amr", - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - gst_bin_add_many (GST_BIN (bin), filesrc, sink, NULL); - - //gst_element_link (source, sink); - gst_element_link_filtered (filesrc, sink, caps); - } - - else - { - /* Create the decodebin */ - decodebin = gst_element_factory_make ("decodebin", NULL); - if (!decodebin) { - //g_print ("could not find the \"decodebin\" element\n"); - return -1; - } - - /* add objects to the main pipeline */ - gst_bin_add_many (GST_BIN (bin), filesrc, decodebin, NULL); - - /* link the elements. */ - gst_element_link_many (filesrc, decodebin, NULL); - - /* Connect to decodebin's 'new-decoded-pad' signal to detect when it produces - * a new stream */ - g_signal_connect (G_OBJECT (decodebin), "new-decoded-pad", - G_CALLBACK (new_decoded_pad), bin); - } - - gst_bus_add_watch( gst_pipeline_get_bus (GST_PIPELINE (bin)), bus_call, NULL); - //g_print ("Starting playback\n"); - /* start playing */ - gst_element_set_state (bin, GST_STATE_PLAYING); - return 0; - -no_output: - return -1; - -} - - -int -gst_record_file (int type) -{ - GstElement *audiosrc, *filesink; - char* carray = NULL; - GstCaps* caps; - //g_print ("Constructing pipeline\n"); - - /* switch case for recording type*/ - switch( type ) - { - case RECORD_RAW: - caps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - carray = "c:\\data\\sounds\\Digital\\record.raw"; - break; - - case RECORD_AMR: - { - return gst_record_amr(); - } - break; - - case RECORD_G711: - - caps = gst_caps_new_simple ("audio/x-alaw", - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - carray = "c:\\data\\sounds\\Digital\\record.g711"; - break; - - case RECORD_G729: // - - caps = gst_caps_new_simple ("audio/g729", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - carray = "c:\\data\\sounds\\Digital\\record.g729"; - break; - - case RECORD_ILBC: // - - caps = gst_caps_new_simple ("audio/ilbc", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - carray = "c:\\data\\sounds\\Digital\\record.ilbc"; - break; - case RECORD_WAV: - { - return gst_record_wav(); - } - break; - case RECORD_AAC: - { - return gst_record_aac(); - } - break; - default: - return -1; - break; - } - /* create a new bin to hold the elements */ - bin = gst_pipeline_new ("pipeline"); - if(!bin) - goto no_output; - - /* create a disk reader */ - audiosrc = gst_element_factory_make ("devsoundsrc", "audio_source"); - if(!audiosrc) - goto no_output; - - /* Create the decodebin */ - filesink = gst_element_factory_make ("filesink", NULL); - if(!filesink) - goto no_output; - - g_object_set (G_OBJECT (audiosrc), - "blocksize", 1280, - NULL); - - g_object_set (G_OBJECT (filesink), "location", carray,"buffer-size",1280, NULL); - - /* add objects to the main pipeline */ - gst_bin_add_many (GST_BIN (bin), audiosrc, filesink, NULL); - - /* link the elements. */ - gst_element_link_filtered (audiosrc, filesink, caps); - //gst_element_link_many (audiosrc, filesink, NULL); - gst_bus_add_watch( gst_pipeline_get_bus (GST_PIPELINE (bin)), bus_call, NULL); - - //g_print ("Starting recoring\n"); - /* start playing */ - gst_element_set_state (bin, GST_STATE_PLAYING); - - /* Run event loop listening for bus messages until EOS or ERROR */ - //event_loop (bin); - -// //g_print ("Finished playback - stopping pipeline\n"); -// -// /* stop the bin */ -// gst_element_set_state (bin, GST_STATE_NULL); -// -// /* Unreffing the bin will clean up all its children too */ -// gst_object_unref (bin); -// - return 0; -no_output: - return -1; - -} - - -int -gst_record_wav () -{ - GstElement *audiosrc, *filesink, *wavenc; - char* carray = NULL; - GstCaps* caps; - - //g_print ("Constructing pipeline\n"); - - /* create a new bin to hold the elements */ - bin = gst_pipeline_new ("pipeline"); - if(!bin) - goto no_output; - - /* create a disk reader */ - audiosrc = gst_element_factory_make ("devsoundsrc", "audio_source"); - if(!audiosrc) - goto no_output; - - /* Create the decodebin */ - filesink = gst_element_factory_make ("filesink", NULL); - if(!filesink) - goto no_output; - - wavenc = gst_element_factory_make ("wavenc", NULL); - if(!wavenc) - goto no_output; - - caps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 16000, - "channels", G_TYPE_INT, 1, NULL); - - carray = "c:\\data\\sounds\\Digital\\record.wav"; - - g_object_set (G_OBJECT (audiosrc), - "blocksize", 1280, - NULL); - - g_object_set (G_OBJECT (filesink), "location", carray,"buffer-size",1280, NULL); - - /* add objects to the main pipeline */ - gst_bin_add_many (GST_BIN (bin), audiosrc,wavenc, filesink, NULL); - - /* link the elements. */ - gst_element_link_filtered (audiosrc, wavenc, caps); - gst_element_link (wavenc, filesink); - gst_bus_add_watch( gst_pipeline_get_bus (GST_PIPELINE (bin)), bus_call, NULL); - //g_print ("Starting recoring\n"); - /* start playing */ - gst_element_set_state (bin, GST_STATE_PLAYING); - - return 0; - -no_output: - return -1; -} - -int gst_pause() -{ - gst_element_set_state (bin, GST_STATE_PAUSED); - return 0; -} - -int gst_resume() -{ - gst_element_set_state (bin, GST_STATE_PLAYING); - return 0; -} - - -int gst_record_stop() -{ - gst_element_send_event (bin, gst_event_new_eos ()); - //gst_element_set_state (bin, GST_STATE_NULL); - return 0; -} - - -int gst_seek() -{ -// need to implement.. -} - -int gst_get_events() -{ - return g_main_context_iteration(NULL, FALSE); - //return 0; -} - -int gst_unref() -{ - //g_print ("Finished playback - stopping pipeline\n"); - /* stop the bin */ - gst_element_set_state (bin, GST_STATE_NULL); - /* Unreffing the bin will clean up all its children too */ - gst_object_unref (bin); - return 0; -} - -int gst_record_aac() -{ - GstElement *audiosrc,*filesink,*aacenc, *mp4mux; - GstBus *bus; - GstPad *mp4sinkpad,*aacencsrcpad; - char* carray = NULL; - GstCaps* caps; - - /*create a pipeline*/ - bin = gst_pipeline_new ("pipeline"); - if(!bin) - goto no_output; - /* create a disk reader */ - audiosrc = gst_element_factory_make ("devsoundsrc", "audio_source"); - if(!audiosrc) - goto no_output; - - /* Create the decodebin */ - filesink = gst_element_factory_make ("filesink", NULL); - if(!filesink) - goto no_output; - //setting num-buffers - //g_object_set (G_OBJECT (audiosrc), "num-buffers", 5000 , NULL); - g_object_set (G_OBJECT (audiosrc), - "blocksize", 1280, - NULL); - - aacenc = gst_element_factory_make("nokiaaacenc", "nokiaaacenc"); - if(!aacenc) - goto no_output; - mp4mux = gst_element_factory_make("mp4mux", "mp4mux"); - if(!mp4mux) - goto no_output; - caps = gst_caps_new_simple("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - carray = "c:\\data\\sounds\\Digital\\record.mp4"; - - - g_object_set(G_OBJECT (filesink), "location", carray, NULL); - bus = gst_pipeline_get_bus(GST_PIPELINE (bin)); - - gst_bus_add_watch(bus, bus_call, NULL); - - gst_object_unref(bus); - - - //add objects to the main pipeline - gst_bin_add_many(GST_BIN (bin),audiosrc,aacenc,mp4mux,filesink, NULL); - - gst_element_link_filtered (audiosrc, aacenc, caps); - - mp4sinkpad = gst_element_get_request_pad( mp4mux, "audio_%d"); - - aacencsrcpad = gst_element_get_pad( aacenc, "src"); - if (gst_pad_link (aacencsrcpad,mp4sinkpad) != GST_PAD_LINK_OK) { - - g_print("gst_pad_link (aacencsrcpad,mp4sinkpad) failed"); - - return -1; - } - //gst_element_link (aacenc, filesink); - gst_element_link (mp4mux, filesink); - - gst_caps_unref (caps); - - - gst_element_set_state(bin, GST_STATE_PLAYING); - - return 0; -no_output: - return -1; -} - -int gst_record_amr() -{ - GstElement *audiosrc, *filesink, *amrmux; - GstBus *bus; - char* carray = NULL; - GstCaps* caps; - /* create a new bin to hold the elements */ - bin = gst_pipeline_new ("pipeline"); - if(!bin) - goto no_output; - //g_print ("pipeline created"); - audiosrc = gst_element_factory_make ("devsoundsrc", "audio_source"); - // encoder = gst_element_factory_make ("wavenc", NULL); - if(!audiosrc) - goto no_output; - - amrmux = gst_element_factory_make ("amrmux", "muxer"); - if(!amrmux) - goto no_output; - - filesink = gst_element_factory_make("filesink", "filesink"); - if(!filesink) - goto no_output; - - caps = gst_caps_new_simple ("audio/amr", - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - carray = "c:\\data\\sounds\\Digital\\record.amr"; - - g_object_set (G_OBJECT (audiosrc), - "blocksize", 1280, - NULL); - - g_object_set(G_OBJECT (filesink), "location", carray, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (bin)); - gst_bus_add_watch (bus, bus_call, NULL); - gst_object_unref (bus); - - - /* add objects to the main pipeline */ - gst_bin_add_many(GST_BIN (bin),audiosrc,amrmux,filesink , NULL); - /* link the elements */ - gst_element_link_filtered (audiosrc, amrmux, caps); - - gst_element_link( amrmux, filesink ); - - gst_element_set_state (bin, GST_STATE_PLAYING); - - return 0; -no_output: - return -1; - -} diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/record_play.h --- a/QtGSTPlayer/record_play.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library 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 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - -#ifndef __HELP_FILE_H__ -#define __HELP_FILE_H__ -#include -#include - -enum -{ - NONE, - PLAYING, - STOP, - PAUSE, - /*RESUME, - RECORDING*/ -}; - -enum -{ - RECORD_NONE, - RECORD_AMR, - RECORD_WAV, - RECORD_RAW, - RECORD_G711, - RECORD_G729, - RECORD_ILBC, - RECORD_AAC -}; - - -#ifdef __cplusplus -extern "C" -{ -#endif - -int gst_play_file( const char* file ); - -int gst_record_file( int type ); - -int gst_record_wav(); - -int gst_pause(); - -int gst_resume(); - -int gst_record_stop(); - -int gst_seek(); - -int gst_unref(); - -int gst_get_events(); - -int gst_record_aac(); - -int gst_record_amr(); - -#ifdef __cplusplus -} -#endif -#endif //__HELP_FILE_H__ - diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/settings.png Binary file QtGSTPlayer/settings.png has changed diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/views.cpp --- a/QtGSTPlayer/views.cpp Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -#include -#include -//#include - -#include "views.h" - -// Helper methods for retrieving the views used in this application -namespace Views { - - // Store the mainwindow ptr here because we cannot call HbWidget::mainWindow() from these static functions. - HbMainWindow *win; - -/*! - Returns the pointer to folder view. -*/ - HbView *folderView() - { - // 0 since folderView was added first to the main window - return win->viewAt(0); - } - -/*! - Returns the pointer to settings view. -*/ - /* HbFormView *settingsView() - { - // 1 since settingsView was the second view added - return static_cast(win->viewAt(1)); - } - */ -} diff -r 5cb7d96a6887 -r 8d4f92b9230e QtGSTPlayer/views.h --- a/QtGSTPlayer/views.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -#ifndef VIEWS_H -#define VIEWS_H - -class HbView; -//class HbFormView; -class HbMainWindow; - -namespace Views -{ - extern HbMainWindow *win; - HbView *folderView(); - //HbFormView *settingsView(); -} - -#endif // VIEWS_H diff -r 5cb7d96a6887 -r 8d4f92b9230e data/gst_dll_2001F41F.txt --- a/data/gst_dll_2001F41F.txt Fri May 28 18:11:17 2010 -0500 +++ b/data/gst_dll_2001F41F.txt Fri Jun 25 17:18:46 2010 -0500 @@ -7,7 +7,6 @@ libgstdecodebin2.dll libgstdevsoundsink.dll libgstdevsoundsrc.dll -libgstapp.dll libgstqueue2.dll libgstadder.dll libgsttypefindfunctions.dll @@ -15,29 +14,13 @@ libgstwavparse.dll libgstaudiotestsrc.dll libgstautodetect.dll -libgstmad.dll -libgstvideorate.dll -libgstvideoscale.dll -libgstvideotestsrc.dll -libgstavi.dll -libgstffmpegcolorspace.dll -libgstmpegstream.dll -libgstmpeg2dec.dll -libgstsdlvideosink.dll -libgstauparse.dll -libgstqtdemux.dll +libgstsubparse.dll +libgsttcp.dll +libgstvolume.dll +libgstplaybin.dll +libgstgdp.dll +libgstapp.dll gstqtmux.dll libgstnokiaaacenc.dll -libgstlibgstqueue2.dll -libgstjpeg.dll -libgstplaybin.dll -libgstgdp.dll -libgstvolume.dll -libgsttcp.dll -libgstsubparse.dll -libgstaudiofx.dll -libgstmulaw.dll -libgstalaw.dll libgstamrmux.dll -libgstmpegaudioparse.dll -libgstnokiaaacdec.dll + diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_nokia_speech/bwins/libgstnokiaaacencu.def --- a/gst_nokia_speech/bwins/libgstnokiaaacencu.def Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_aac_enc_get_type @ 2 NONAME - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_nokia_speech/config.h --- a/gst_nokia_speech/config.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -/* config.h. Generated by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* defined if cdda headers are in a cdda/ directory */ -/* #undef CDPARANOIA_HEADERS_IN_DIR */ - -/* Default audio sink */ -#define DEFAULT_AUDIOSINK "autoaudiosink" - -/* Default audio source */ -#define DEFAULT_AUDIOSRC "alsasrc" - -/* Default video sink */ -#define DEFAULT_VIDEOSINK "autovideosink" - -/* Default video source */ -#define DEFAULT_VIDEOSRC "v4lsrc" - -/* Default visualizer */ -#define DEFAULT_VISUALIZER "goom" - -/* Define to 1 if translation of program messages to the user's native - language is requested. */ -#ifdef __SYMBIAN32__ -#undef ENABLE_NLS -#else -#define ENABLE_NLS 1 -#endif - - -/* gettext package name */ -#define GETTEXT_PACKAGE "gst-plugins-base-0.10" - -/* macro to use to show function name */ -#define GST_FUNCTION __PRETTY_FUNCTION__ - -/* Defined if gcov is enabled to force a rebuild due to config.h changing */ -/* #undef GST_GCOV_ENABLED */ - -/* Default errorlevel to use */ -#define GST_LEVEL_DEFAULT GST_LEVEL_NONE - -/* GStreamer license */ -#define GST_LICENSE "LGPL" - -/* package name in plugins */ -#define GST_PACKAGE_NAME "GStreamer Base Plug-ins source release" - -/* package origin */ -#define GST_PACKAGE_ORIGIN "Unknown package origin" - -/* support for features: gstalsa */ -#define HAVE_ALSA - -/* support for features: cdparanoia */ -/* #undef HAVE_CDPARANOIA */ - -/* Define if the host CPU is an Alpha */ -/* #undef HAVE_CPU_ALPHA */ - -/* Define if the host CPU is an ARM */ -/* #undef HAVE_CPU_ARM */ -#ifdef __SYMBIAN32__ -#define HAVE_CPU_ARM 1 -#endif - -/* Define if the host CPU is a CRIS */ -/* #undef HAVE_CPU_CRIS */ - -/* Define if the host CPU is a CRISv32 */ -/* #undef HAVE_CPU_CRISV32 */ - -/* Define if the host CPU is a HPPA */ -/* #undef HAVE_CPU_HPPA */ - -/* Define if the host CPU is an x86 */ -#ifndef __SYMBIAN32__ -#define HAVE_CPU_I386 1 -#endif -/* Define if the host CPU is a IA64 */ -/* #undef HAVE_CPU_IA64 */ - -/* Define if the host CPU is a M68K */ -/* #undef HAVE_CPU_M68K */ - -/* Define if the host CPU is a MIPS */ -/* #undef HAVE_CPU_MIPS */ - -/* Define if the host CPU is a PowerPC */ -/* #undef HAVE_CPU_PPC */ - -/* Define if the host CPU is a 64 bit PowerPC */ -/* #undef HAVE_CPU_PPC64 */ - -/* Define if the host CPU is a S390 */ -/* #undef HAVE_CPU_S390 */ - -/* Define if the host CPU is a SPARC */ -/* #undef HAVE_CPU_SPARC */ - -/* Define if the host CPU is a x86_64 */ -/* #undef HAVE_CPU_X86_64 */ - -/* Define if the GNU dcgettext() function is already present or preinstalled. - */ -#define HAVE_DCGETTEXT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* support for features: */ -#define HAVE_EXTERNAL - -/* FIONREAD ioctl found in sys/filio.h */ -/* #undef HAVE_FIONREAD_IN_SYS_FILIO */ - -/* FIONREAD ioctl found in sys/ioclt.h */ -#define HAVE_FIONREAD_IN_SYS_IOCTL 1 - -/* defined if the compiler implements __func__ */ -#define HAVE_FUNC 1 - -/* defined if the compiler implements __FUNCTION__ */ -#define HAVE_FUNCTION 1 - -/* Define if the GNU gettext() function is already present or preinstalled. */ -#define HAVE_GETTEXT 1 - -/* support for features: gnomevfssrc */ -#define HAVE_GNOME_VFS - -/* support for features: v4lsrc v4lmjpegsrc v4lmjpegsink */ -#define HAVE_GST_V4L - -/* Define if you have the iconv() function. */ -/* #undef HAVE_ICONV */ - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `asound' library (-lasound). */ -/* #undef HAVE_LIBASOUND */ - -/* support for features: libvisual */ -/* #undef HAVE_LIBVISUAL */ - -/* Define if you have C99's lrint function. */ -#define HAVE_LRINT 1 - -/* Define if you have C99's lrintf function. */ -#define HAVE_LRINTF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MALLOC_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* support for features: oggdemux oggmux */ -#define HAVE_OGG - -/* support for features: pango */ -#define HAVE_PANGO - -/* defined if the compiler implements __PRETTY_FUNCTION__ */ -#define HAVE_PRETTY_FUNCTION 1 - -/* Define if RDTSC is available */ -#define HAVE_RDTSC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_REGEX_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* support for features: theoradec theoraenc */ -/* #undef HAVE_THEORA */ - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define if valgrind should be used */ -#define HAVE_VALGRIND 1 - -/* support for features: vorbisenc vorbisdec */ -#define HAVE_VORBIS - -/* defined if vorbis_synthesis_restart is present */ -#define HAVE_VORBIS_SYNTHESIS_RESTART 1 - -/* support for features: ximagesink */ -#define HAVE_X - -/* support for features: xshm */ -#define HAVE_XSHM - -/* support for features: xvimagesink */ -#define HAVE_XVIDEO - -/* gettext locale dir */ -#define LOCALEDIR "/home/datha/gst-plugins-base-0.10.8/share/locale" - -/* Name of package */ -#define PACKAGE "gst-plugins-base" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "GStreamer nokia speech" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "GStreamer nokia speech" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "gst_nokia_speech" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.10.0" - -/* directory where plugins are located */ - -/* The size of a `char', as computed by sizeof. */ -/* #undef SIZEOF_CHAR */ - -/* The size of a `int', as computed by sizeof. */ -/* #undef SIZEOF_INT */ - -/* The size of a `long', as computed by sizeof. */ -/* #undef SIZEOF_LONG */ - -/* The size of a `short', as computed by sizeof. */ -/* #undef SIZEOF_SHORT */ - -/* The size of a `void*', as computed by sizeof. */ -/* #undef SIZEOF_VOIDP */ - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "0.10.0" - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* Define to 1 if the X Window System is missing or not being used. */ -/* #undef X_DISPLAY_MISSING */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_nokia_speech/eabi/libgstnokiaaacencu.def --- a/gst_nokia_speech/eabi/libgstnokiaaacencu.def Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_aac_enc_get_type @ 2 NONAME - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_nokia_speech/group/bld.inf --- a/gst_nokia_speech/group/bld.inf Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -PRJ_PLATFORMS -DEFAULT - -PRJ_EXPORTS - -PRJ_MMPFILES -#ifndef WINSCW -gstaacenc.mmp -#endif \ No newline at end of file diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_nokia_speech/group/gstaacenc.mmp --- a/gst_nokia_speech/group/gstaacenc.mmp Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -// Gstreamer.MMP -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library 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 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - -#include - -TARGET libgstnokiaaacenc.dll -TARGETTYPE DLL -UID 0x20004c45 0x0FE80A1C - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO HAVE_CONFIG_H //RAW_FRAME_SIZE - - -USERINCLUDE .. - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE - -USERINCLUDE ../../include/gstreamer -USERINCLUDE ../../include/gstreamer/gst -USERINCLUDE ../../include/gstreamer/gst/base -USERINCLUDE ../../include/gstreamer/gst/controller -USERINCLUDE ../../include/gstreamer/gst/dataprotocol -USERINCLUDE ../../include/gstreamer/gst/net -USERINCLUDE ../../include/gstreamer/gst/audio -USERINCLUDE ../../include/gstreamer/gst/cdda -USERINCLUDE ../../include/gstreamer/gst/floatcast -USERINCLUDE ../../include/gstreamer/gst/interfaces -USERINCLUDE ../../include/gstreamer/gst/netbuffer -USERINCLUDE ../../include/gstreamer/gst/riff -USERINCLUDE ../../include/gstreamer/gst/rtp -USERINCLUDE ../../include/gstreamer/gst/tag -USERINCLUDE ../../include/gstreamer/gst/video -SYSTEMINCLUDE /epoc32/include/internal -SOURCEPATH .. -SOURCE gstaacenc.c gstframedaudioenc.c -LIBRARY euser.lib -LIBRARY libc.lib -LIBRARY libdl.lib -LIBRARY libglib.lib -LIBRARY libgmodule.lib - -LIBRARY libgobject.lib -LIBRARY libgthread.lib -LIBRARY libm.lib -LIBRARY libz.lib -LIBRARY libgstreamer.lib -LIBRARY enhaacplusencoder.lib -LIBRARY libgstbase.lib - -#ifdef WINSCW -LIBRARY ewsd.lib //wsd solution -#endif - - - -SMPSAFE diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_nokia_speech/gstaacenc.c --- a/gst_nokia_speech/gstaacenc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,603 +0,0 @@ -/* GStreamer AAC encoder - * Copyright 2009 Collabora Multimedia, - * Copyright 2009 Nokia Corporation - * @author: Mark Nauwelaerts . - * - * 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. - */ - -/* TODO non-GPL license */ - -/** - * SECTION:element-nokiaaacenc - * @seealso: nokiaaacdec - * - * nokiaaacenc encodes raw audio to AAC streams. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include - -#include "gstaacenc.h" - -GST_DEBUG_CATEGORY_STATIC (aac_enc); -#define GST_CAT_DEFAULT aac_enc - -enum -{ - AAC_PROFILE_AUTO = 0, - AAC_PROFILE_LC = 2, - AAC_PROFILE_HE = 5 -}; - -#define GST_TYPE_AAC_ENC_PROFILE (gst_aac_enc_profile_get_type ()) -static GType -gst_aac_enc_profile_get_type (void) -{ - static GType gst_aac_enc_profile_type = 0; - - if (!gst_aac_enc_profile_type) { - static GEnumValue gst_aac_enc_profile[] = { - {AAC_PROFILE_AUTO, "Codec selects LC or HE", "AUTO"}, - {AAC_PROFILE_LC, "Low complexity profile", "LC"}, - {AAC_PROFILE_HE, "High Efficiency", "HE"}, - {0, NULL, NULL}, - }; - - gst_aac_enc_profile_type = g_enum_register_static ("GstNokiaAacEncProfile", - gst_aac_enc_profile); - } - - return gst_aac_enc_profile_type; -} - -#define GST_TYPE_AAC_ENC_OUTPUTFORMAT (gst_aac_enc_outputformat_get_type ()) -static GType -gst_aac_enc_outputformat_get_type (void) -{ - static GType gst_aac_enc_outputformat_type = 0; - - if (!gst_aac_enc_outputformat_type) { - static GEnumValue gst_aac_enc_outputformat[] = { - {RAW, "AAC Raw format", "RAW"}, - {USE_ADTS, "Audio Data Transport Stream format", "ADTS"}, - {USE_ADIF, "Audio Data Interchange Format", "ADIF"}, - {0, NULL, NULL}, - }; - - gst_aac_enc_outputformat_type = - g_enum_register_static ("GstNokiaAacEncOutputFormat", - gst_aac_enc_outputformat); - } - - return gst_aac_enc_outputformat_type; -} - -enum -{ - PROP_0, - PROP_BITRATE, - PROP_PROFILE, - PROP_FORMAT -}; - -static GstStaticPadTemplate gst_aac_enc_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "endianness = (int) BYTE_ORDER, " - "signed = (bool) TRUE, " - "width = (int) 16, " - "depth = (int) 16, " - "rate = (int) [ 8000, 96000 ], channels = (int) [ 1, 2 ] ") - ); - -static GstStaticPadTemplate gst_aac_enc_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/mpeg, " "mpegversion = (int) 4, " - "rate = (int) [ 8000, 96000 ], channels = (int) [ 1, 2 ] ") - ); - -static void gst_aac_enc_base_init (gpointer g_class); -static void gst_aac_enc_class_init (GstAACEncClass * klass); -static void gst_aac_enc_init (GstAACEnc * filter, GstAACEncClass * klass); - -static void gst_aac_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_aac_enc_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static void gst_aac_enc_finalize (GObject * object); -static void gst_aac_enc_reset (GstAACEnc * enc); -static GstStateChangeReturn gst_aac_enc_change_state (GstElement * element, - GstStateChange transition); -static gboolean gst_aac_enc_sink_setcaps (GstPad * pad, GstCaps * caps); -static GstFlowReturn gst_aac_enc_chain (GstPad * pad, GstBuffer * buffer); - -GST_BOILERPLATE (GstNokiaAACEnc, gst_aac_enc, GstElement, GST_TYPE_ELEMENT); - -static void -gst_aac_enc_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details_simple (element_class, - "Nokia AAC encoder", "Codec/Encoder/Audio", - "Nokia AAC encoder", - "MCC, Mark Nauwelaerts "); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_aac_enc_src_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_aac_enc_sink_template)); -} - -/* initialize the plugin's class */ -static void -gst_aac_enc_class_init (GstAACEncClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - GST_DEBUG_CATEGORY_INIT (aac_enc, "nokiaaacenc", 0, "Nokia AAC encoder"); - - gobject_class->set_property = gst_aac_enc_set_property; - gobject_class->get_property = gst_aac_enc_get_property; - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_aac_enc_finalize); - - /* properties */ - g_object_class_install_property (gobject_class, PROP_BITRATE, - g_param_spec_int ("bitrate", "Bitrate (bps)", "Bitrate in bits/sec", - 8 * 1000, 320 * 1000, 128 * 1000, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_CONSTRUCT))); - g_object_class_install_property (gobject_class, PROP_PROFILE, - g_param_spec_enum ("profile", "Profile", - "MPEG/AAC encoding profile", - GST_TYPE_AAC_ENC_PROFILE, AAC_PROFILE_LC, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (gobject_class, PROP_FORMAT, - g_param_spec_enum ("output-format", "Output format", - "Format of output frames", - GST_TYPE_AAC_ENC_OUTPUTFORMAT, RAW, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_aac_enc_change_state); -} - -static void -gst_aac_enc_init (GstAACEnc * enc, GstAACEncClass * klass) -{ - enc->sinkpad = - gst_pad_new_from_static_template (&gst_aac_enc_sink_template, "sink"); - gst_pad_set_setcaps_function (enc->sinkpad, - GST_DEBUG_FUNCPTR (gst_aac_enc_sink_setcaps)); - gst_pad_set_chain_function (enc->sinkpad, - GST_DEBUG_FUNCPTR (gst_aac_enc_chain)); - gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad); - - enc->srcpad = - gst_pad_new_from_static_template (&gst_aac_enc_src_template, "src"); - gst_pad_use_fixed_caps (enc->srcpad); - gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad); - -#ifndef GST_DISABLE_GST_DEBUG - gst_framed_audio_enc_init (&enc->enc, GST_ELEMENT (enc), aac_enc); -#else - gst_framed_audio_enc_init (&enc->enc, GST_ELEMENT (enc), NULL); -#endif - - gst_aac_enc_reset (enc); -} - -static void -gst_aac_enc_reset (GstAACEnc * enc) -{ - gst_framed_audio_enc_reset (&enc->enc); - if (enc->encoder) - EnAACPlus_Enc_Delete (enc->encoder); - enc->encoder = NULL; - g_free (enc->buffer); - enc->buffer = NULL; -} - -static void -gst_aac_enc_finalize (GObject * object) -{ - GstAACEnc *enc = (GstAACEnc *) object; - - gst_framed_audio_enc_finalize (&enc->enc); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -gst_aac_enc_setup_encoder (GstAACEnc * enc) -{ - AACPLUS_ENC_CONFIG enc_params; - AACPLUS_ENC_MODE mode; - gint rate, channels; - guint maxbitrate; - - rate = enc->rate; - channels = enc->channels; - - /* only up to 2 channels supported */ - enc_params.sampleRate = rate; - enc_params.bitRate = enc->bitrate; - enc_params.nChannels = channels; - enc_params.aac_tools = USE_ALL; - enc_params.pcm_mode = 16; - enc_params.format = enc->format; - - /* check, warn and correct if the max bitrate for the given samplerate is - * exceeded. Maximum of 6144 bit for a channel */ - maxbitrate = - (guint) (6144.0 * (gdouble) rate / (gdouble) 1024.0 + .5) * channels; - if (enc_params.bitRate > maxbitrate) { - GST_ELEMENT_INFO (enc, RESOURCE, SETTINGS, (NULL), - ("bitrate %d exceeds maximum allowed bitrate of %d for samplerate %d " - "and %d channels. Setting bitrate to %d", - enc_params.bitRate, maxbitrate, rate, channels, maxbitrate)); - enc_params.bitRate = maxbitrate; - } - - /* set up encoder */ - if (enc->encoder) - EnAACPlus_Enc_Delete (enc->encoder); - - /* only these profiles are really known to and supported by codec */ - switch (enc->profile) { - case AAC_PROFILE_LC: - mode = MODE_AACLC; - break; - case AAC_PROFILE_HE: - mode = MODE_EAACPLUS; - break; - case AAC_PROFILE_AUTO: - mode = MODE_AUTO; - break; - default: - mode = MODE_AACLC; - g_assert_not_reached (); - break; - } - enc->encoder = EnAACPlus_Enc_Create (&enc_params, mode); - - if (!enc->encoder) - goto setup_failed; - - /* query and setup params, - * also set up some buffers for fancy HE */ - EnAACPlus_Enc_GetSetParam (enc->encoder, &enc->info); - -#define DUMP_FIELD(f) \ - GST_DEBUG_OBJECT (enc, "encoder info: " G_STRINGIFY (f) " = %d", enc->info.f); - - DUMP_FIELD (InBufSize); - DUMP_FIELD (OutBufSize); - DUMP_FIELD (Frame_Size); - DUMP_FIELD (writeOffset); - DUMP_FIELD (InBufSize); - - enc->raw_frame_size = enc->info.Frame_Size; - enc->codec_frame_size = enc->info.OutBufSize; - enc->frame_duration = - GST_FRAMES_TO_CLOCK_TIME (enc->raw_frame_size / enc->channels / 2, - enc->rate); - - g_free (enc->buffer); - /* safety margin */ - enc->buffer = g_malloc (enc->info.InBufSize * 2); - - return TRUE; - - /* ERRORS */ -setup_failed: - { - GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL)); - return FALSE; - } -} - -static gint -gst_aac_enc_rate_idx (gint rate) -{ - static int rates[] = { - 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, - 8000, 7350 - }; - guint i; - - for (i = 0; i < G_N_ELEMENTS (rates); ++i) - if (rates[i] == rate) - return i; - - return 0xF; -} - -static gboolean -gst_aac_enc_sink_setcaps (GstPad * pad, GstCaps * caps) -{ - GstAACEnc *enc; - gboolean ret = TRUE; - GstStructure *s; - GstBuffer *buf = NULL; - gint rate, channels; - - enc = GST_AAC_ENC (GST_PAD_PARENT (pad)); - - /* extract stream properties */ - s = gst_caps_get_structure (caps, 0); - - if (!s) - goto refuse_caps; - - ret = gst_structure_get_int (s, "rate", &rate); - ret &= gst_structure_get_int (s, "channels", &channels); - - if (!ret) - goto refuse_caps; - - enc->rate = rate; - enc->channels = channels; - - /* NOTE: - * - codec only supports LC or HE (= LC + SBR etc) - * - HE has (more) restrictive samplerate/channels/bitrate combination - * - AUTO makes codec select between LC or HE (depending on settings) - */ - - gst_aac_enc_setup_encoder (enc); - if (!enc->encoder) - return FALSE; - - /* HE iff writeOffset <> 0 iff Frame_Size <> 1024 * 2 * channels */ - if (enc->info.writeOffset) - rate /= 2; - - /* create codec_data if raw output */ - if (enc->format == RAW) { - gint rate_idx; - guint8 *data; - - buf = gst_buffer_new_and_alloc (5); - data = GST_BUFFER_DATA (buf); - rate_idx = gst_aac_enc_rate_idx (rate); - - GST_DEBUG_OBJECT (enc, "codec_data: profile=%d, sri=%d, channels=%d", - enc->profile, rate_idx, enc->channels); - - /* always write LC profile, and use implicit signaling for HE SBR */ - data[0] = ((2 & 0x1F) << 3) | ((rate_idx & 0xE) >> 1); - data[1] = ((rate_idx & 0x1) << 7); - if (rate_idx != 0x0F) { - data[1] |= ((channels & 0xF) << 3); - GST_BUFFER_SIZE (buf) = 2; - } else { - gint srate; - - srate = rate << 7; - data[1] |= ((srate >> 24) & 0xFF); - data[2] = ((srate >> 16) & 0xFF); - data[3] = ((srate >> 8) & 0xFF); - data[4] = (srate & 0xFF); - data[4] |= ((channels & 0xF) << 3); - GST_BUFFER_SIZE (buf) = 5; - } - } - - /* fix some in src template */ - caps = gst_caps_copy (gst_pad_get_pad_template_caps (enc->srcpad)); - gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate, - "channels", G_TYPE_INT, channels, NULL); - if (buf) { - gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); - } - ret = gst_pad_set_caps (enc->srcpad, caps); - gst_caps_unref (caps); - - return ret; - - /* ERRORS */ -refuse_caps: - { - GST_WARNING_OBJECT (enc, "refused caps %" GST_PTR_FORMAT, caps); - return FALSE; - } -} - -static gint -gst_aac_enc_get_data (GstElement * element, const guint8 * in, guint8 * out, - GstDtxDecision * dtx) -{ - GstAACEnc *enc; - gint res; - gint offset; - UWord32 used, encoded; - Word8 *inbuffer; - - enc = GST_AAC_ENC_CAST (element); - - offset = enc->info.writeOffset; - if (offset) { - memcpy (enc->buffer + offset, in, enc->raw_frame_size); - inbuffer = (Word8 *) enc->buffer; - } else { - inbuffer = (Word8 *) in; - } - - res = EnAACPlus_Enc_Encode (enc->encoder, &enc->info, inbuffer, &used, - (UWord8 *) out, &encoded); - - if (offset) { - memcpy (enc->buffer, enc->buffer + used, offset); - } - - return res == 0 ? encoded : -1; -} - -/* set parameters */ -#define AUDIO_SAMPLE_RATE ((GST_AAC_ENC (enc->element))->rate) -#define RAW_FRAME_SIZE ((GST_AAC_ENC (enc->element))->raw_frame_size) -/* safe maximum frame size */ -#define CODEC_FRAME_SIZE ((GST_AAC_ENC (enc->element))->codec_frame_size) -/* do not set variable frame; - * this will make every frame act as a silence frame and force output */ -/* #define CODEC_FRAME_VARIABLE 1 */ -#define FRAME_DURATION ((GST_AAC_ENC (enc->element))->frame_duration) -#define codec_get_data(enc, in, out, dtx) \ - gst_aac_enc_get_data (enc, in, out, dtx) - -/* and include code */ -#include "gstframedaudioenc.c" - -static GstFlowReturn -gst_aac_enc_chain (GstPad * pad, GstBuffer * buf) -{ - GstAACEnc *enc; - - enc = GST_AAC_ENC (GST_PAD_PARENT (pad)); - - if (G_UNLIKELY (enc->encoder == NULL)) - goto not_negotiated; - - return gst_framed_audio_enc_chain (&enc->enc, buf, enc->srcpad, &enc->cnpad); - - /* ERRORS */ -not_negotiated: - { - GST_ELEMENT_ERROR (enc, CORE, NEGOTIATION, (NULL), - ("format wasn't negotiated before chain function")); - gst_buffer_unref (buf); - return GST_FLOW_NOT_NEGOTIATED; - } -} - -static void -gst_aac_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAACEnc *enc; - - enc = GST_AAC_ENC (object); - - switch (prop_id) { - case PROP_BITRATE: - enc->bitrate = g_value_get_int (value); - break; - case PROP_PROFILE: - enc->profile = g_value_get_enum (value); - break; - case PROP_FORMAT: - enc->format = g_value_get_enum (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_aac_enc_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAACEnc *enc; - - enc = GST_AAC_ENC (object); - - switch (prop_id) { - case PROP_BITRATE: - g_value_set_int (value, enc->bitrate); - break; - case PROP_PROFILE: - g_value_set_enum (value, enc->profile); - break; - case PROP_FORMAT: - g_value_set_enum (value, enc->format); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_aac_enc_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstAACEnc *enc = GST_AAC_ENC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_aac_enc_reset (enc); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - - if (!gst_element_register (plugin, "nokiaaacenc", GST_RANK_SECONDARY, - GST_TYPE_AAC_ENC)) - return FALSE; - - return TRUE; -} - -/* this is the structure that gst-register looks for - * so keep the name plugin_desc, or you cannot get your plug-in registered */ -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "nokiaaacenc", - "Nokia AAC MCC codec", - plugin_init, VERSION, "Proprietary", "gst-nokia-speech", "") - -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() - { - return &gst_plugin_desc; - } - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_nokia_speech/gstaacenc.h --- a/gst_nokia_speech/gstaacenc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* GStreamer AAC encoder - * Copyright 2009 Collabora Multimedia, - * Copyright 2009 Nokia Corporation - * @author: Mark Nauwelaerts . - * - * 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. - */ - -/* TODO non-GPL license */ - -#ifndef __GST_AAC_ENC_H__ -#define __GST_AAC_ENC_H__ - -#include - -#include - -#include "gstframedaudioenc.h" - -G_BEGIN_DECLS - -/* #define's don't like whitespacey bits */ -#define GST_TYPE_AAC_ENC \ - (gst_aac_enc_get_type()) -#define GST_AAC_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AAC_ENC,GstAACEnc)) -#define GST_AAC_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AAC_ENC,GstAACEncClass)) -#define GST_IS_AAC_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AAC_ENC)) -#define GST_IS_AAC_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AAC_ENC)) -#define GST_AAC_ENC_CAST(obj) ((GstAACEnc*)(obj)) - - -typedef struct _GstNokiaAACEnc GstNokiaAACEnc; -typedef struct _GstNokiaAACEncClass GstNokiaAACEncClass; - -typedef GstNokiaAACEnc GstAACEnc; -typedef GstNokiaAACEncClass GstAACEncClass; - -struct _GstNokiaAACEnc -{ - GstElement element; - - GstPad *sinkpad, *srcpad, *cnpad; - - GstFramedAudioEnc enc; - HANDLE_AACPLUS_ENC encoder; - AACPLUS_ENC_INFO info; - - /* mode selection */ - GstClockTime frame_duration; - gint raw_frame_size; - gint codec_frame_size; - - /* optional helper (history) buffer */ - guint8 *buffer; - - /* stream description */ - gint rate; - gint channels; - - /* properties */ - gint bitrate; - guint profile; - guint format; -}; - -struct _GstNokiaAACEncClass -{ - GstElementClass parent_class; -}; - -GType gst_aac_enc_get_type (void); - -G_END_DECLS - -#endif /* __GST_AAC_ENC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_nokia_speech/gstframedaudioenc.c --- a/gst_nokia_speech/gstframedaudioenc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,439 +0,0 @@ -/* GStreamer Framed Audio Encoder - * Copyright 2009 Collabora Ltd, - * Copyright 2009 Nokia Corporation - * @author: Mark Nauwelaerts . - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include - -#include "gstframedaudioenc.h" - -/* generic part */ -#ifndef RAW_FRAME_SIZE - -/* this will reference caller's debug category; - * there is a copy of this per plugin lib (= debug category) */ -GST_DEBUG_CATEGORY_STATIC (framedaudioenc_debug); -#define GST_CAT_DEFAULT framedaudioenc_debug - -void -gst_framed_audio_enc_reset (GstFramedAudioEnc * enc) -{ - gst_adapter_clear (enc->adapter); - enc->next_ts = GST_CLOCK_TIME_NONE; -} - -/* installs @enc as element private for @element's pad, - * and possibly some event and query handler. - * if these need overriding, chain up to them - * chain and setcaps still need to be set by @element */ -void -gst_framed_audio_enc_init (GstFramedAudioEnc * enc, GstElement * element, - GstDebugCategory * cat) -{ - enc->element = element; -#ifndef GST_DISABLE_GST_DEBUG - framedaudioenc_debug = cat; -#endif - - enc->adapter = gst_adapter_new (); - - /* hook some */ - enc->sinkpad = gst_element_get_pad (enc->element, "sink"); - g_assert (enc->sinkpad); - gst_pad_set_element_private (enc->sinkpad, enc); - - /* watch downstream events */ - gst_pad_set_event_function (enc->sinkpad, - GST_DEBUG_FUNCPTR (gst_framed_audio_enc_sink_event)); - - gst_framed_audio_enc_reset (enc); -} - -void -gst_framed_audio_enc_finalize (GstFramedAudioEnc * enc) -{ - gst_object_unref (enc->adapter); - - gst_pad_set_element_private (enc->sinkpad, NULL); - gst_object_unref (enc->sinkpad); -} - -GstPad * -gst_framed_audio_enc_request_new_pad (GstFramedAudioEnc * enc, - GstPadTemplate * templ, const gchar * req_name, GstPad ** pad_p) -{ - GstElement *element; - GstPad *newpad; - GstElementClass *klass; - GstCaps *caps; - - g_return_val_if_fail (templ != NULL, NULL); - - element = enc->element; - klass = GST_ELEMENT_GET_CLASS (element); - - if (templ != gst_element_class_get_pad_template (klass, "cn")) - goto wrong_template; - - GST_DEBUG_OBJECT (enc->element, "adding cn pad"); - newpad = gst_pad_new_from_template (templ, "cn"); - /* set template caps */ - caps = gst_caps_copy (gst_pad_get_pad_template_caps (newpad)); - gst_pad_set_caps (newpad, caps); - gst_caps_unref (caps); - gst_pad_use_fixed_caps (newpad); - gst_pad_set_active (newpad, TRUE); - /* only 1 pad by name can be added */ - if (gst_element_add_pad (element, newpad)) { - GST_OBJECT_LOCK (element); - gst_object_replace ((GstObject **) pad_p, GST_OBJECT_CAST (newpad)); - GST_OBJECT_UNLOCK (element); - GST_DEBUG_OBJECT (enc->element, "cn pad added"); - } else { - gst_object_unref (newpad); - goto already_requested; - } - - return newpad; - - /* ERRORS */ -wrong_template: - { - GST_ERROR_OBJECT (element, "not our template!"); - return NULL; - } -already_requested: - { - GST_ERROR_OBJECT (element, "only 1 instance of a pad can be requested"); - return NULL; - } -} - -void -gst_framed_audio_enc_release_pad (GstFramedAudioEnc * enc, GstPad * pad, - GstPad ** pad_p, void (disable_cn) (GstElement *)) -{ - GstElement *element = enc->element; - - GST_DEBUG_OBJECT (enc->element, "releasing cn pad"); - - GST_OBJECT_LOCK (element); - if (pad != *pad_p) - goto wrong_pad; - GST_OBJECT_UNLOCK (element); - - /* reconfigure encoder */ - disable_cn (element); - - if (gst_element_remove_pad (element, pad)) { - GST_OBJECT_LOCK (element); - gst_object_replace ((GstObject **) pad_p, NULL); - GST_OBJECT_UNLOCK (element); - GST_DEBUG_OBJECT (enc->element, "cn pad released"); - } - - /* ERRORS */ -wrong_pad: - { - GST_OBJECT_UNLOCK (element); - GST_ERROR_OBJECT (element, "pad not requested; can not be released!"); - return; - } -} - -gboolean -gst_framed_audio_enc_sink_event (GstPad * pad, GstEvent * event) -{ - GstFramedAudioEnc *enc; - - enc = gst_pad_get_element_private (pad); - g_return_val_if_fail (enc, FALSE); - - GST_LOG_OBJECT (enc->element, "received %s", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_STOP: - /* fall-through */ - case GST_EVENT_EOS: - gst_adapter_clear (enc->adapter); - enc->next_ts = GST_CLOCK_TIME_NONE; - break; - default: - break; - } - - return gst_pad_event_default (pad, event); -} - -#else -/* included part */ - -/* parameters: - RAW_FRAME_SIZE - CODEC_FRAME_SIZE - FRAME_DURATION - AUDIO_SAMPLE_RATE (optional) - callback: - codec_get_data(enc, in, out, dtx) - - If one does not mind a few cycles, include'ing can also be replaced by - a regular include & call, at the expense of some additional parameters - passed some way or another. -*/ - -#ifndef AUDIO_SAMPLE_RATE -#define AUDIO_SAMPLE_RATE (8000) -#endif - -/* quite some conditional stuff; - * the (ugly?) cost of trying to stay inner loop optimal */ - -static GstFlowReturn -gst_framed_audio_enc_chain (GstFramedAudioEnc * enc, GstBuffer * buf, - GstPad * srcpad, GstPad ** _cnpad) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstBuffer *obuf = NULL; -#ifdef CN_PAD - GstBuffer *cnbuf = NULL; - GstPad *cnpad = NULL; -#endif - gboolean discont = FALSE; - const guint8 *data; - guint8 *odata; - gint av, flush, osize; - -#ifdef CN_PAD - GST_OBJECT_LOCK (enc->element); - if (_cnpad) - cnpad = *_cnpad; - if (cnpad) - gst_object_ref (cnpad); - GST_OBJECT_UNLOCK (enc->element); -#endif - - if (G_LIKELY (buf)) { - GST_LOG_OBJECT (enc->element, "input buffer of size %d with ts: %" - GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); - discont = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT); - - /* reposition to the new buffer's timestamp, - * while correcting for some minor left-over */ - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - if (GST_CLOCK_TIME_IS_VALID (enc->next_ts)) { - GstClockTimeDiff diff, limit; - GstClockTime tleft; - - tleft = GST_FRAMES_TO_CLOCK_TIME - (gst_adapter_available (enc->adapter) / 2, AUDIO_SAMPLE_RATE); - diff = - GST_CLOCK_DIFF (enc->next_ts + tleft, GST_BUFFER_TIMESTAMP (buf)); - limit = GST_SECOND / AUDIO_SAMPLE_RATE / 2; - /* try for a perfect stream if possible, do not act on rounding errors */ - if (diff > limit || diff < -limit) { - enc->next_ts = GST_BUFFER_TIMESTAMP (buf); - if (enc->next_ts > tleft) - enc->next_ts -= tleft; - GST_LOG_OBJECT (enc->element, "marking discont based on timestamps"); - discont = TRUE; - } - } else - enc->next_ts = GST_BUFFER_TIMESTAMP (buf); - } - - gst_adapter_push (enc->adapter, buf); - buf = NULL; - } - - av = gst_adapter_available (enc->adapter); - if (G_UNLIKELY (av < RAW_FRAME_SIZE)) - goto done; - - data = gst_adapter_peek (enc->adapter, av); - obuf = gst_buffer_new_and_alloc (av / RAW_FRAME_SIZE * CODEC_FRAME_SIZE); - odata = GST_BUFFER_DATA (obuf); - osize = 0; - flush = 0; - - while (TRUE) { - gint esize; -#ifdef CN_PAD - GstDtxDecision dtx; - - /* safe default to start with, should get set */ - dtx = GST_DTX_DECISION_VOICE; - esize = codec_get_data (enc->element, data + flush, odata, &dtx); -#else - esize = codec_get_data (enc->element, data + flush, odata, NULL); -#endif - - if (G_UNLIKELY (esize < 0)) - goto encode_failed; - -#ifdef CN_PAD - /* cn in a separate stream */ - switch (dtx) { - case GST_DTX_DECISION_VOICE: -#endif - flush += RAW_FRAME_SIZE; - av -= RAW_FRAME_SIZE; - - odata += esize; - osize += esize; -#ifdef CN_PAD - break; - case GST_DTX_DECISION_SID_UPDATE: - GST_LOG_OBJECT (enc->element, "dtx: SID_UPDATE %d", esize); - /* if already data before, need to put SID data separately */ - if (G_UNLIKELY (osize)) { - cnbuf = gst_buffer_new_and_alloc (esize); - memcpy (GST_BUFFER_DATA (cnbuf), data + osize, esize); - } else { - cnbuf = obuf; - obuf = NULL; - } - /* and send one or both */ - goto send; - break; - case GST_DTX_DECISION_SID_NONE: - GST_LOG_OBJECT (enc->element, "dtx: SID_NONE %d", esize); - /* maybe send preceding voice, if any */ - goto send; - break; - } -#endif - -#ifdef CODEC_FRAME_VARIABLE - /* flush output after insufficient data */ - if (av >= RAW_FRAME_SIZE) - continue; -#else - /* ... or some reduced (e.g. silence) frame */ - if (esize >= CODEC_FRAME_SIZE && av >= RAW_FRAME_SIZE) - continue; -#endif - -#ifdef CN_PAD - send: -#endif - /* maybe a silent discarded frame */ - if (G_LIKELY (osize)) { - GST_BUFFER_SIZE (obuf) = osize; - GST_BUFFER_DURATION (obuf) - = FRAME_DURATION * (flush / RAW_FRAME_SIZE); - GST_BUFFER_TIMESTAMP (obuf) = enc->next_ts; - if (G_UNLIKELY (discont)) { - GST_BUFFER_FLAG_SET (obuf, GST_BUFFER_FLAG_DISCONT); - discont = FALSE; - } - - GST_LOG_OBJECT (enc->element, - "pushing buffer of size %d with ts: %" GST_TIME_FORMAT, - GST_BUFFER_SIZE (obuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (obuf))); - gst_buffer_set_caps (obuf, GST_PAD_CAPS (srcpad)); - ret = gst_pad_push (srcpad, obuf); - obuf = NULL; - } else { - ret = GST_FLOW_OK; - } - -#ifdef CN_PAD - /* check for stuff to send on cn pad */ - if (cnbuf && cnpad) { - /* only at most 1 SID update per buffer */ - GST_BUFFER_SIZE (cnbuf) = esize; - GST_BUFFER_DURATION (cnbuf) = FRAME_DURATION; - GST_BUFFER_TIMESTAMP (cnbuf) = enc->next_ts; - - GST_LOG_OBJECT (enc->element, - "pushing cn buffer of size %d with ts: %" GST_TIME_FORMAT, - GST_BUFFER_SIZE (cnbuf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (cnbuf))); - gst_buffer_set_caps (cnbuf, GST_PAD_CAPS (cnpad)); - if (G_LIKELY (ret == GST_FLOW_OK)) { - ret = gst_pad_push (cnpad, cnbuf); - /* cn pad may not be linked */ - if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) - ret = GST_FLOW_OK; - } else - gst_pad_push (cnpad, cnbuf); - cnbuf = NULL; - } else if (G_UNLIKELY (cnbuf)) { - /* should not occur */ - gst_buffer_unref (cnbuf); - cnbuf = NULL; - } - - if (dtx != GST_DTX_DECISION_VOICE) { - /* still need to count non-voice encoded frame */ - flush += RAW_FRAME_SIZE; - av -= RAW_FRAME_SIZE; - } -#endif /* CN_PAD */ - - /* remove used part */ - gst_adapter_flush (enc->adapter, flush); - if (GST_CLOCK_TIME_IS_VALID (enc->next_ts)) - enc->next_ts += FRAME_DURATION * (flush / RAW_FRAME_SIZE); - - /* end if insufficient left or error */ - if (av < RAW_FRAME_SIZE || ret != GST_FLOW_OK) - break; - - /* allocate new buffer */ - if (!obuf) { - obuf = gst_buffer_new_and_alloc (av / RAW_FRAME_SIZE * CODEC_FRAME_SIZE); - odata = GST_BUFFER_DATA (obuf); - osize = 0; - } - /* and prepare to consume again */ - data = gst_adapter_peek (enc->adapter, av); - flush = 0; - } - - if (!av) { - enc->next_ts = GST_CLOCK_TIME_NONE; - } - -done: -#ifdef CN_PAD - GST_OBJECT_LOCK (enc->element); - if (cnpad) - gst_object_unref (cnpad); - GST_OBJECT_UNLOCK (enc->element); -#endif - - return ret; - - /* ERRORS */ -encode_failed: - { - GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), (NULL)); - ret = GST_FLOW_ERROR; - gst_buffer_unref (obuf); - goto done; - } -} -#endif diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_nokia_speech/gstframedaudioenc.h --- a/gst_nokia_speech/gstframedaudioenc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* GStreamer Framed Audio Encoder - * Copyright 2009 Collabora Ltd, - * Copyright 2009 Nokia Corporation - * @author: Mark Nauwelaerts . - * - * 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. - */ - -#ifndef __GST_FRAMED_AUDIO_ENC_H__ -#define __GST_FRAMED_AUDIO_ENC_H__ - -#include -#include - -G_BEGIN_DECLS - -typedef struct _GstNokiaFramedAudioEnc GstNokiaFramedAudioEnc; -typedef struct _GstNokiaFramedAudioEncClass GstNokiaFramedAudioEncClass; - -typedef GstNokiaFramedAudioEnc GstFramedAudioEnc; -typedef GstNokiaFramedAudioEncClass GstFramedAudioEncClass; - -struct _GstNokiaFramedAudioEnc -{ - /* helper for this element */ - GstElement *element; - - /* private stuff */ - - /* pad with incoming data */ - GstPad *sinkpad; - - GstAdapter *adapter; - GstClockTime next_ts; -}; - -typedef enum _GstDtxDecision { - GST_DTX_DECISION_VOICE, - GST_DTX_DECISION_SID_UPDATE, - GST_DTX_DECISION_SID_NONE -} GstDtxDecision; - -void gst_framed_audio_enc_init (GstFramedAudioEnc * enc, GstElement * element, - GstDebugCategory * cat); -void gst_framed_audio_enc_reset (GstFramedAudioEnc * enc); -void gst_framed_audio_enc_finalize (GstFramedAudioEnc * enc); -GstPad * gst_framed_audio_enc_request_new_pad (GstFramedAudioEnc * enc, - GstPadTemplate * templ, const gchar * req_name, GstPad ** pad_p); -void gst_framed_audio_enc_release_pad (GstFramedAudioEnc * enc, GstPad * pad, - GstPad ** pad_p, void (disable_cn) (GstElement *)); -gboolean gst_framed_audio_enc_sink_event (GstPad * pad, GstEvent * event); - -G_END_DECLS - -#endif /* __GST_FRAMED_AUDIO_ENC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsa.c --- a/gst_plugins_base/ext/alsa/gstalsa.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,556 +0,0 @@ -/* Copyright (C) 2006 Tim-Philipp Müller - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "gstalsa.h" - -#include - -static GstCaps * -gst_alsa_detect_rates (GstObject * obj, snd_pcm_hw_params_t * hw_params, - GstCaps * in_caps) -{ - GstCaps *caps; - guint min, max; - gint err, dir, min_rate, max_rate, i; - - GST_LOG_OBJECT (obj, "probing sample rates ..."); - - if ((err = snd_pcm_hw_params_get_rate_min (hw_params, &min, &dir)) < 0) - goto min_rate_err; - - if ((err = snd_pcm_hw_params_get_rate_max (hw_params, &max, &dir)) < 0) - goto max_rate_err; - - min_rate = min; - max_rate = max; - - if (min_rate < 4000) - min_rate = 4000; /* random 'sensible minimum' */ - - if (max_rate <= 0) - max_rate = G_MAXINT; /* or maybe just use 192400 or so? */ - else if (max_rate > 0 && max_rate < 4000) - max_rate = MAX (4000, min_rate); - - GST_DEBUG_OBJECT (obj, "Min. rate = %u (%d)", min_rate, min); - GST_DEBUG_OBJECT (obj, "Max. rate = %u (%d)", max_rate, max); - - caps = gst_caps_make_writable (in_caps); - - for (i = 0; i < gst_caps_get_size (caps); ++i) { - GstStructure *s; - - s = gst_caps_get_structure (caps, i); - if (min_rate == max_rate) { - gst_structure_set (s, "rate", G_TYPE_INT, min_rate, NULL); - } else { - gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, - min_rate, max_rate, NULL); - } - } - - return caps; - - /* ERRORS */ -min_rate_err: - { - GST_ERROR_OBJECT (obj, "failed to query minimum sample rate: %s", - snd_strerror (err)); - gst_caps_unref (in_caps); - return NULL; - } -max_rate_err: - { - GST_ERROR_OBJECT (obj, "failed to query maximum sample rate: %s", - snd_strerror (err)); - gst_caps_unref (in_caps); - return NULL; - } -} - -static const struct -{ - const int width; - const int depth; - const int sformat; - const int uformat; -} pcmformats[] = { - { - 8, 8, SND_PCM_FORMAT_S8, SND_PCM_FORMAT_U8}, { - 16, 16, SND_PCM_FORMAT_S16, SND_PCM_FORMAT_U16}, { - 32, 24, SND_PCM_FORMAT_S24, SND_PCM_FORMAT_U24}, { -#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) /* no endian-unspecific enum available */ - 24, 24, SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_U24_3LE}, { -#else - 24, 24, SND_PCM_FORMAT_S24_3BE, SND_PCM_FORMAT_U24_3BE}, { -#endif - 32, 32, SND_PCM_FORMAT_S32, SND_PCM_FORMAT_U32} -}; - -static GstCaps * -gst_alsa_detect_formats (GstObject * obj, snd_pcm_hw_params_t * hw_params, - GstCaps * in_caps) -{ - snd_pcm_format_mask_t *mask; - GstStructure *s; - GstCaps *caps; - gint i; - - snd_pcm_format_mask_malloc (&mask); - snd_pcm_hw_params_get_format_mask (hw_params, mask); - - caps = gst_caps_new_empty (); - - for (i = 0; i < gst_caps_get_size (in_caps); ++i) { - GstStructure *scopy; - gint w, width = 0, depth = 0; - - s = gst_caps_get_structure (in_caps, i); - if (!gst_structure_has_name (s, "audio/x-raw-int")) { - GST_WARNING_OBJECT (obj, "skipping non-int format"); - continue; - } - if (!gst_structure_get_int (s, "width", &width) || - !gst_structure_get_int (s, "depth", &depth)) - continue; - if (width == 0 || (width % 8) != 0) - continue; /* Only full byte widths are valid */ - for (w = 0; w < G_N_ELEMENTS (pcmformats); w++) - if (pcmformats[w].width == width && pcmformats[w].depth == depth) - break; - if (w == G_N_ELEMENTS (pcmformats)) - continue; /* Unknown format */ - - if (snd_pcm_format_mask_test (mask, pcmformats[w].sformat) && - snd_pcm_format_mask_test (mask, pcmformats[w].uformat)) { - /* template contains { true, false } or just one, leave it as it is */ - scopy = gst_structure_copy (s); - } else if (snd_pcm_format_mask_test (mask, pcmformats[w].sformat)) { - scopy = gst_structure_copy (s); - gst_structure_set (scopy, "signed", G_TYPE_BOOLEAN, TRUE, NULL); - } else if (snd_pcm_format_mask_test (mask, pcmformats[w].uformat)) { - scopy = gst_structure_copy (s); - gst_structure_set (scopy, "signed", G_TYPE_BOOLEAN, FALSE, NULL); - } else { - scopy = NULL; - } - if (scopy) { - if (width > 8) { - /* TODO: proper endianness detection, for now it's CPU endianness only */ - gst_structure_set (scopy, "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL); - } - gst_caps_append_structure (caps, scopy); - } - } - - snd_pcm_format_mask_free (mask); - gst_caps_unref (in_caps); - return caps; -} - -/* we don't have channel mappings for more than this many channels */ -#define GST_ALSA_MAX_CHANNELS 8 - -static GstStructure * -get_channel_free_structure (const GstStructure * in_structure) -{ - GstStructure *s = gst_structure_copy (in_structure); - - gst_structure_remove_field (s, "channels"); - return s; -} - -static void -caps_add_channel_configuration (GstCaps * caps, - const GstStructure * in_structure, gint min_chans, gint max_chans) -{ - GstAudioChannelPosition pos[8] = { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, - GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, - GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT - }; - GstStructure *s = NULL; - gint c; - - if (min_chans == max_chans && max_chans <= 2) { - s = get_channel_free_structure (in_structure); - gst_structure_set (s, "channels", G_TYPE_INT, max_chans, NULL); - gst_caps_append_structure (caps, s); - return; - } - - g_assert (min_chans >= 1); - - /* mono and stereo don't need channel configurations */ - if (min_chans == 2) { - s = get_channel_free_structure (in_structure); - gst_structure_set (s, "channels", G_TYPE_INT, 2, NULL); - gst_caps_append_structure (caps, s); - } else if (min_chans == 1 && max_chans >= 2) { - s = get_channel_free_structure (in_structure); - gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); - gst_caps_append_structure (caps, s); - } - - /* don't know whether to use 2.1 or 3.0 here - but I suspect - * alsa might work around that/fix it somehow. Can we tell alsa - * what our channel layout is like? */ - if (max_chans >= 3 && min_chans <= 3) { - GstAudioChannelPosition pos_21[3] = { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_LFE - }; - - s = get_channel_free_structure (in_structure); - gst_structure_set (s, "channels", G_TYPE_INT, 3, NULL); - gst_audio_set_channel_positions (s, pos_21); - gst_caps_append_structure (caps, s); - } - - /* everything else (4, 6, 8 channels) needs a channel layout */ - for (c = MAX (4, min_chans); c <= 8; c += 2) { - if (max_chans >= c) { - s = get_channel_free_structure (in_structure); - gst_structure_set (s, "channels", G_TYPE_INT, c, NULL); - gst_audio_set_channel_positions (s, pos); - gst_caps_append_structure (caps, s); - } - } - - for (c = MAX (9, min_chans); c <= max_chans; ++c) { - GstAudioChannelPosition *ch_layout; - guint i; - - ch_layout = g_new (GstAudioChannelPosition, c); - for (i = 0; i < c; ++i) { - ch_layout[i] = GST_AUDIO_CHANNEL_POSITION_NONE; - } - s = get_channel_free_structure (in_structure); - gst_structure_set (s, "channels", G_TYPE_INT, c, NULL); - gst_audio_set_channel_positions (s, ch_layout); - gst_caps_append_structure (caps, s); - g_free (ch_layout); - } -} - -static GstCaps * -gst_alsa_detect_channels (GstObject * obj, snd_pcm_hw_params_t * hw_params, - GstCaps * in_caps) -{ - GstCaps *caps; - guint min, max; - gint min_chans, max_chans; - gint err, i; - - GST_LOG_OBJECT (obj, "probing channels ..."); - - if ((err = snd_pcm_hw_params_get_channels_min (hw_params, &min)) < 0) - goto min_chan_error; - - if ((err = snd_pcm_hw_params_get_channels_max (hw_params, &max)) < 0) - goto max_chan_error; - - /* note: the above functions may return (guint) -1 */ - min_chans = min; - max_chans = max; - - if (min_chans < 0) { - min_chans = 1; - max_chans = GST_ALSA_MAX_CHANNELS; - } else if (max_chans < 0) { - max_chans = GST_ALSA_MAX_CHANNELS; - } - - if (min_chans > max_chans) { - gint temp; - - GST_WARNING_OBJECT (obj, "minimum channels > maximum channels (%d > %d), " - "please fix your soundcard drivers", min, max); - temp = min_chans; - min_chans = max_chans; - max_chans = temp; - } - - /* pro cards seem to return large numbers for min_channels */ - if (min_chans > GST_ALSA_MAX_CHANNELS) { - GST_DEBUG_OBJECT (obj, "min_chans = %u, looks like a pro card", min_chans); - if (max_chans < min_chans) { - max_chans = min_chans; - } else { - /* only support [max_chans; max_chans] for these cards for now - * to avoid inflating the source caps with loads of structures ... */ - min_chans = max_chans; - } - } else { - min_chans = MAX (min_chans, 1); - max_chans = MIN (GST_ALSA_MAX_CHANNELS, max_chans); - } - - GST_DEBUG_OBJECT (obj, "Min. channels = %d (%d)", min_chans, min); - GST_DEBUG_OBJECT (obj, "Max. channels = %d (%d)", max_chans, max); - - caps = gst_caps_new_empty (); - - for (i = 0; i < gst_caps_get_size (in_caps); ++i) { - GstStructure *s; - GType field_type; - gint c_min = min_chans; - gint c_max = max_chans; - - s = gst_caps_get_structure (in_caps, i); - /* the template caps might limit the number of channels (like alsasrc), - * in which case we don't want to return a superset, so hack around this - * for the two common cases where the channels are either a fixed number - * or a min/max range). Example: alsasrc template has channels = [1,2] and - * the detection will claim to support 8 channels for device 'plughw:0' */ - field_type = gst_structure_get_field_type (s, "channels"); - if (field_type == G_TYPE_INT) { - gst_structure_get_int (s, "channels", &c_min); - gst_structure_get_int (s, "channels", &c_max); - } else if (field_type == GST_TYPE_INT_RANGE) { - const GValue *val; - - val = gst_structure_get_value (s, "channels"); - c_min = CLAMP (gst_value_get_int_range_min (val), min_chans, max_chans); - c_max = CLAMP (gst_value_get_int_range_max (val), min_chans, max_chans); - } else { - c_min = min_chans; - c_max = max_chans; - } - - caps_add_channel_configuration (caps, s, c_min, c_max); - } - - gst_caps_unref (in_caps); - - return caps; - - /* ERRORS */ -min_chan_error: - { - GST_ERROR_OBJECT (obj, "failed to query minimum channel count: %s", - snd_strerror (err)); - return NULL; - } -max_chan_error: - { - GST_ERROR_OBJECT (obj, "failed to query maximum channel count: %s", - snd_strerror (err)); - return NULL; - } -} - -snd_pcm_t * -gst_alsa_open_iec958_pcm (GstObject * obj) -{ - char *iec958_pcm_name = NULL; - snd_pcm_t *pcm = NULL; - int res; - char devstr[256]; /* Storage for local 'default' device string */ - - /* - * Try and open our default iec958 device. Fall back to searching on card x - * if this fails, which should only happen on older alsa setups - */ - - /* The string will be one of these: - * SPDIF_CON: Non-audio flag not set: - * spdif:{AES0 0x0 AES1 0x82 AES2 0x0 AES3 0x2} - * SPDIF_CON: Non-audio flag set: - * spdif:{AES0 0x2 AES1 0x82 AES2 0x0 AES3 0x2} - */ - sprintf (devstr, - "iec958:{AES0 0x%02x AES1 0x%02x AES2 0x%02x AES3 0x%02x}", - IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO, - IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER, - 0, IEC958_AES3_CON_FS_48000); - - GST_DEBUG_OBJECT (obj, "Generated device string \"%s\"", devstr); - iec958_pcm_name = devstr; - - res = snd_pcm_open (&pcm, iec958_pcm_name, SND_PCM_STREAM_PLAYBACK, 0); - if (G_UNLIKELY (res < 0)) { - GST_DEBUG_OBJECT (obj, "failed opening IEC958 device: %s", - snd_strerror (res)); - pcm = NULL; - } - - return pcm; -} - - -/* - * gst_alsa_probe_supported_formats: - * - * Takes the template caps and returns the subset which is actually - * supported by this device. - * - */ - -GstCaps * -gst_alsa_probe_supported_formats (GstObject * obj, snd_pcm_t * handle, - const GstCaps * template_caps) -{ - snd_pcm_hw_params_t *hw_params; - snd_pcm_stream_t stream_type; - GstCaps *caps; - gint err; - - snd_pcm_hw_params_malloc (&hw_params); - if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) - goto error; - - stream_type = snd_pcm_stream (handle); - - caps = gst_caps_copy (template_caps); - - if (!(caps = gst_alsa_detect_formats (obj, hw_params, caps))) - goto subroutine_error; - - if (!(caps = gst_alsa_detect_rates (obj, hw_params, caps))) - goto subroutine_error; - - if (!(caps = gst_alsa_detect_channels (obj, hw_params, caps))) - goto subroutine_error; - - /* Try opening IEC958 device to see if we can support that format (playback - * only for now but we could add SPDIF capture later) */ - if (stream_type == SND_PCM_STREAM_PLAYBACK) { - snd_pcm_t *pcm = gst_alsa_open_iec958_pcm (obj); - - if (G_LIKELY (pcm)) { - gst_caps_append (caps, gst_caps_new_simple ("audio/x-iec958", NULL)); - snd_pcm_close (pcm); - } - } - - snd_pcm_hw_params_free (hw_params); - return caps; - - /* ERRORS */ -error: - { - GST_ERROR_OBJECT (obj, "failed to query formats: %s", snd_strerror (err)); - snd_pcm_hw_params_free (hw_params); - return NULL; - } -subroutine_error: - { - GST_ERROR_OBJECT (obj, "failed to query formats"); - snd_pcm_hw_params_free (hw_params); - return NULL; - } -} - -static gchar * -gst_alsa_find_device_name_no_handle (GstObject * obj, const gchar * devcard, - gint device_num, snd_pcm_stream_t stream) -{ - snd_ctl_card_info_t *info = NULL; - snd_ctl_t *ctl = NULL; - gchar *ret = NULL; - gint dev = -1; - - GST_LOG_OBJECT (obj, "[%s] device=%d", devcard, device_num); - - if (snd_ctl_open (&ctl, devcard, 0) < 0) - return NULL; - - snd_ctl_card_info_malloc (&info); - if (snd_ctl_card_info (ctl, info) < 0) - goto done; - - while (snd_ctl_pcm_next_device (ctl, &dev) == 0 && dev >= 0) { - if (dev == device_num) { - snd_pcm_info_t *pcminfo; - - snd_pcm_info_malloc (&pcminfo); - snd_pcm_info_set_device (pcminfo, dev); - snd_pcm_info_set_subdevice (pcminfo, 0); - snd_pcm_info_set_stream (pcminfo, stream); - if (snd_ctl_pcm_info (ctl, pcminfo) < 0) { - snd_pcm_info_free (pcminfo); - break; - } - - ret = g_strdup (snd_pcm_info_get_name (pcminfo)); - snd_pcm_info_free (pcminfo); - GST_LOG_OBJECT (obj, "name from pcminfo: %s", GST_STR_NULL (ret)); - } - } - - if (ret == NULL) { - char *name = NULL; - gint card; - - GST_LOG_OBJECT (obj, "no luck so far, trying backup"); - card = snd_ctl_card_info_get_card (info); - snd_card_get_name (card, &name); - ret = g_strdup (name); - free (name); - } - -done: - snd_ctl_card_info_free (info); - snd_ctl_close (ctl); - - return ret; -} - -gchar * -gst_alsa_find_device_name (GstObject * obj, const gchar * device, - snd_pcm_t * handle, snd_pcm_stream_t stream) -{ - gchar *ret = NULL; - - if (device != NULL) { - gchar *dev, *comma; - gint devnum; - - GST_LOG_OBJECT (obj, "Trying to get device name from string '%s'", device); - - /* only want name:card bit, but not devices and subdevices */ - dev = g_strdup (device); - if ((comma = strchr (dev, ','))) { - *comma = '\0'; - devnum = atoi (comma + 1); - ret = gst_alsa_find_device_name_no_handle (obj, dev, devnum, stream); - } - g_free (dev); - } - - if (ret == NULL && handle != NULL) { - snd_pcm_info_t *info; - - GST_LOG_OBJECT (obj, "Trying to get device name from open handle"); - snd_pcm_info_malloc (&info); - snd_pcm_info (handle, info); - ret = g_strdup (snd_pcm_info_get_name (info)); - snd_pcm_info_free (info); - } - - GST_LOG_OBJECT (obj, "Device name for device '%s': %s", - GST_STR_NULL (device), GST_STR_NULL (ret)); - - return ret; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsa.h --- a/gst_plugins_base/ext/alsa/gstalsa.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2001 CodeFactory AB - * Copyright (C) 2001 Thomas Nyberg - * Copyright (C) 2001-2002 Andy Wingo - * Copyright (C) 2003 Benjamin Otte - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#ifndef __GST_ALSA_H__ -#define __GST_ALSA_H__ - - -#define ALSA_PCM_NEW_HW_PARAMS_API -#define ALSA_PCM_NEW_SW_PARAMS_API - -#include -#include -#include -#include - -#define GST_CHECK_ALSA_VERSION(major,minor,micro) \ - (SND_LIB_MAJOR > (major) || \ - (SND_LIB_MAJOR == (major) && SND_LIB_MINOR > (minor)) || \ - (SND_LIB_MAJOR == (major) && SND_LIB_MINOR == (minor) && \ - SND_LIB_SUBMINOR >= (micro))) - -GST_DEBUG_CATEGORY_EXTERN (alsa_debug); -#define GST_CAT_DEFAULT alsa_debug - -snd_pcm_t * gst_alsa_open_iec958_pcm (GstObject * obj); - -GstCaps * gst_alsa_probe_supported_formats (GstObject * obj, - snd_pcm_t * handle, - const GstCaps * template_caps); - -gchar * gst_alsa_find_device_name (GstObject * obj, - const gchar * device, - snd_pcm_t * handle, - snd_pcm_stream_t stream); - -#endif /* __GST_ALSA_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsadeviceprobe.c --- a/gst_plugins_base/ext/alsa/gstalsadeviceprobe.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,208 +0,0 @@ -/* Copyright (C) 2001 CodeFactory AB - * Copyright (C) 2001 Thomas Nyberg - * Copyright (C) 2001-2002 Andy Wingo - * Copyright (C) 2003 Benjamin Otte - * Copyright (C) 2005 Tim-Philipp Müller - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstalsadeviceprobe.h" -#include "gst/interfaces/propertyprobe.h" - -static const GList * -gst_alsa_device_property_probe_get_properties (GstPropertyProbe * probe) -{ - GObjectClass *klass = G_OBJECT_GET_CLASS (probe); - static GList *list = NULL; - - /* well, not perfect, but better than no locking at all. - * In the worst case we leak a list node, so who cares? */ - GST_CLASS_LOCK (GST_OBJECT_CLASS (klass)); - - if (!list) { - GParamSpec *pspec; - - pspec = g_object_class_find_property (klass, "device"); - list = g_list_append (NULL, pspec); - } - - GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass)); - - return list; -} - -static GList * -gst_alsa_get_device_list (snd_pcm_stream_t stream) -{ - snd_ctl_t *handle; - int card, err, dev; - snd_ctl_card_info_t *info; - snd_pcm_info_t *pcminfo; - gboolean mixer = (stream == -1); - GList *list = NULL; - - if (stream == -1) - stream = 0; - - snd_ctl_card_info_malloc (&info); - snd_pcm_info_malloc (&pcminfo); - card = -1; - - if (snd_card_next (&card) < 0 || card < 0) { - /* no soundcard found */ - return NULL; - } - - while (card >= 0) { - gchar name[32]; - - g_snprintf (name, sizeof (name), "hw:%d", card); - if ((err = snd_ctl_open (&handle, name, 0)) < 0) { - goto next_card; - } - if ((err = snd_ctl_card_info (handle, info)) < 0) { - snd_ctl_close (handle); - goto next_card; - } - - if (mixer) { - list = g_list_append (list, g_strdup (name)); - } else { - dev = -1; - while (1) { - gchar *gst_device; - - snd_ctl_pcm_next_device (handle, &dev); - - if (dev < 0) - break; - snd_pcm_info_set_device (pcminfo, dev); - snd_pcm_info_set_subdevice (pcminfo, 0); - snd_pcm_info_set_stream (pcminfo, stream); - if ((err = snd_ctl_pcm_info (handle, pcminfo)) < 0) { - continue; - } - - gst_device = g_strdup_printf ("hw:%d,%d", card, dev); - list = g_list_append (list, gst_device); - } - } - snd_ctl_close (handle); - next_card: - if (snd_card_next (&card) < 0) { - break; - } - } - - snd_ctl_card_info_free (info); - snd_pcm_info_free (pcminfo); - - return list; -} - -static void -gst_alsa_device_property_probe_probe_property (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - if (!g_str_equal (pspec->name, "device")) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - } -} - -static gboolean -gst_alsa_device_property_probe_needs_probe (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - /* don't cache probed data */ - return TRUE; -} - -static GValueArray * -gst_alsa_device_property_probe_get_values (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstElementClass *klass; - const GList *templates; - snd_pcm_stream_t mode = -1; - GValueArray *array; - GValue value = { 0, }; - GList *l, *list; - - if (!g_str_equal (pspec->name, "device")) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - return NULL; - } - - klass = GST_ELEMENT_GET_CLASS (GST_ELEMENT (probe)); - - /* I'm pretty sure ALSA has a good way to do this. However, their cool - * auto-generated documentation is pretty much useless if you try to - * do function-wise look-ups. */ - /* we assume one pad template at max [zero=mixer] */ - templates = gst_element_class_get_pad_template_list (klass); - if (templates) { - if (GST_PAD_TEMPLATE_DIRECTION (templates->data) == GST_PAD_SRC) - mode = SND_PCM_STREAM_CAPTURE; - else - mode = SND_PCM_STREAM_PLAYBACK; - } - - list = gst_alsa_get_device_list (mode); - - if (list == NULL) { - GST_LOG_OBJECT (probe, "No devices found"); - return NULL; - } - - array = g_value_array_new (g_list_length (list)); - g_value_init (&value, G_TYPE_STRING); - for (l = list; l != NULL; l = l->next) { - GST_LOG_OBJECT (probe, "Found device: %s", (gchar *) l->data); - g_value_take_string (&value, (gchar *) l->data); - l->data = NULL; - g_value_array_append (array, &value); - } - g_value_unset (&value); - g_list_free (list); - - return array; -} - -static void -gst_alsa_property_probe_interface_init (GstPropertyProbeInterface * iface) -{ - iface->get_properties = gst_alsa_device_property_probe_get_properties; - iface->probe_property = gst_alsa_device_property_probe_probe_property; - iface->needs_probe = gst_alsa_device_property_probe_needs_probe; - iface->get_values = gst_alsa_device_property_probe_get_values; -} - -void -gst_alsa_type_add_device_property_probe_interface (GType type) -{ - static const GInterfaceInfo probe_iface_info = { - (GInterfaceInitFunc) gst_alsa_property_probe_interface_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, - &probe_iface_info); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsadeviceprobe.h --- a/gst_plugins_base/ext/alsa/gstalsadeviceprobe.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* Copyright (C) 2001 CodeFactory AB - * Copyright (C) 2001 Thomas Nyberg - * Copyright (C) 2001-2002 Andy Wingo - * Copyright (C) 2003 Benjamin Otte - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __GST_ALSA_DEVICE_PROBE_H__ -#define __GST_ALSA_DEVICE_PROBE_H__ - -#include "gstalsa.h" - -G_BEGIN_DECLS - -void gst_alsa_type_add_device_property_probe_interface (GType type); - -G_END_DECLS - -#endif /* __GST_ALSA_DEVICE_PROBE_H__ */ - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsamixer.c --- a/gst_plugins_base/ext/alsa/gstalsamixer.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,887 +0,0 @@ -/* ALSA mixer implementation. - * Copyright (C) 2003 Leif Johnson - * - * 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. - */ - -/** - * SECTION:element-alsamixer - * @short_description: control properties of an audio device - * @see_also: alsasink, alsasrc - * - * - * - * This element controls various aspects such as the volume and balance - * of an audio device using the ALSA api. - * - * - * The application should query and use the interfaces provided by this - * element to control the device. - * - * - * - * Last reviewed on 2006-03-01 (0.10.4) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstalsamixer.h" - -static void gst_alsa_mixer_update_option (GstAlsaMixer * mixer, - GstAlsaMixerOptions * alsa_opts); -static void gst_alsa_mixer_update_track (GstAlsaMixer * mixer, - GstAlsaMixerTrack * alsa_track); -static int gst_alsa_mixer_handle_callback (snd_mixer_t * handle, - unsigned int mask, snd_mixer_elem_t * elem); - -/* First some utils, then the mixer implementation */ -static gboolean -gst_alsa_mixer_open (GstAlsaMixer * mixer) -{ - gint err; - snd_ctl_t *ctl; - snd_ctl_card_info_t *card_info; - - g_return_val_if_fail (mixer->handle == NULL, FALSE); - - /* open and initialize the mixer device */ - err = snd_mixer_open (&mixer->handle, 0); - if (err < 0 || mixer->handle == NULL) - goto open_failed; - - if ((err = snd_mixer_attach (mixer->handle, mixer->device)) < 0) { - GST_WARNING ("Cannot open mixer for sound device '%s': %s", mixer->device, - snd_strerror (err)); - goto error; - } - - if ((err = snd_mixer_selem_register (mixer->handle, NULL, NULL)) < 0) { - GST_WARNING ("Cannot register mixer elements: %s", snd_strerror (err)); - goto error; - } - - if ((err = snd_mixer_load (mixer->handle)) < 0) { - GST_WARNING ("Cannot load mixer settings: %s", snd_strerror (err)); - goto error; - } - - snd_mixer_set_callback_private (mixer->handle, mixer); - snd_mixer_set_callback (mixer->handle, gst_alsa_mixer_handle_callback); - - /* now get the device name, any of this is not fatal */ - g_free (mixer->cardname); - if ((err = snd_ctl_open (&ctl, mixer->device, 0)) < 0) { - GST_WARNING ("Cannot open CTL: %s", snd_strerror (err)); - goto no_card_name; - } - - snd_ctl_card_info_malloc (&card_info); - if ((err = snd_ctl_card_info (ctl, card_info)) < 0) { - GST_WARNING ("Cannot get card info: %s", snd_strerror (err)); - snd_ctl_close (ctl); - goto no_card_name; - } - - mixer->cardname = g_strdup (snd_ctl_card_info_get_name (card_info)); - GST_DEBUG ("Card name = %s", GST_STR_NULL (mixer->cardname)); - snd_ctl_card_info_free (card_info); - snd_ctl_close (ctl); - -no_card_name: - if (mixer->cardname == NULL) { - mixer->cardname = g_strdup ("Unknown"); - GST_DEBUG ("Cannot find card name"); - } - - GST_INFO ("Successfully opened mixer for device '%s'.", mixer->device); - - return TRUE; - - /* ERROR */ -open_failed: - { - GST_WARNING ("Cannot open mixer: %s", snd_strerror (err)); - mixer->handle = NULL; - return FALSE; - } -error: - { - snd_mixer_close (mixer->handle); - mixer->handle = NULL; - return FALSE; - } -} - -static snd_mixer_elem_t * -gst_alsa_mixer_find_master_mixer (GstAlsaMixer * mixer, snd_mixer_t * handle) -{ - snd_mixer_elem_t *element; - gint i, count; - - count = snd_mixer_get_count (handle); - - /* Check if we have a playback mixer labelled as 'Master' */ - element = snd_mixer_first_elem (handle); - for (i = 0; i < count; i++) { - if (snd_mixer_selem_has_playback_volume (element) && - strcmp (snd_mixer_selem_get_name (element), "Master") == 0) { - return element; - } - element = snd_mixer_elem_next (element); - } - - /* If not, check if we have a playback mixer labelled as 'Front' */ - element = snd_mixer_first_elem (handle); - for (i = 0; i < count; i++) { - if (snd_mixer_selem_has_playback_volume (element) && - strcmp (snd_mixer_selem_get_name (element), "Front") == 0) { - return element; - } - element = snd_mixer_elem_next (element); - } - - /* If not, check if we have a playback mixer labelled as 'PCM' */ - element = snd_mixer_first_elem (handle); - for (i = 0; i < count; i++) { - if (snd_mixer_selem_has_playback_volume (element) && - strcmp (snd_mixer_selem_get_name (element), "PCM") == 0) { - return element; - } - element = snd_mixer_elem_next (element); - } - - /* If not, check if we have a playback mixer with both volume and switch */ - element = snd_mixer_first_elem (handle); - for (i = 0; i < count; i++) { - if (snd_mixer_selem_has_playback_volume (element) && - snd_mixer_selem_has_playback_switch (element)) { - return element; - } - element = snd_mixer_elem_next (element); - } - - /* If not, take any playback mixer with a volume control */ - element = snd_mixer_first_elem (handle); - for (i = 0; i < count; i++) { - if (snd_mixer_selem_has_playback_volume (element)) { - return element; - } - element = snd_mixer_elem_next (element); - } - - /* Looks like we're out of luck ... */ - return NULL; -} - -static void -gst_alsa_mixer_update (GstAlsaMixer * mixer, snd_mixer_elem_t * elem) -{ - GList *item; - - g_return_if_fail (mixer != NULL); - - g_static_rec_mutex_lock (mixer->rec_mutex); - - for (item = mixer->tracklist; item != NULL; item = item->next) { - if (GST_IS_ALSA_MIXER_TRACK (item->data)) { - if (elem && (GST_ALSA_MIXER_TRACK (item->data)->element != elem)) - continue; - - gst_alsa_mixer_update_track (mixer, GST_ALSA_MIXER_TRACK (item->data)); - } else if (GST_IS_ALSA_MIXER_OPTIONS (item->data)) { - if (elem && (GST_ALSA_MIXER_OPTIONS (item->data)->element != elem)) - continue; - - gst_alsa_mixer_update_option (mixer, GST_ALSA_MIXER_OPTIONS (item->data)); - } - } - - g_static_rec_mutex_unlock (mixer->rec_mutex); -} - -static int -gst_alsa_mixer_elem_handle_callback (snd_mixer_elem_t * elem, unsigned int mask) -{ - GstAlsaMixer *mixer = - (GstAlsaMixer *) snd_mixer_elem_get_callback_private (elem); - - GST_LOG ("ALSA elem cb"); - - g_return_val_if_fail (mixer != NULL, 1); - - gst_alsa_mixer_update (mixer, elem); - - return 0; -} - -static int -gst_alsa_mixer_handle_callback (snd_mixer_t * handle, unsigned int mask, - snd_mixer_elem_t * elem) -{ - GstAlsaMixer *mixer = - (GstAlsaMixer *) snd_mixer_get_callback_private (handle); - - GST_LOG ("ALSA cb"); - - g_return_val_if_fail (mixer != NULL, 1); - - /* Hopefully won't be call recursively and will handle pending elem events */ - snd_mixer_handle_events (mixer->handle); - - gst_alsa_mixer_update (mixer, elem); - - return 0; -} - -static void -gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer) -{ - gint i, count; - snd_mixer_elem_t *element, *master; - GList *item; - - g_return_if_fail (mixer->handle != NULL); - - if (mixer->tracklist) - return; - - g_static_rec_mutex_lock (mixer->rec_mutex); - - master = gst_alsa_mixer_find_master_mixer (mixer, mixer->handle); - - count = snd_mixer_get_count (mixer->handle); - element = snd_mixer_first_elem (mixer->handle); - - /* build track list - * - * Some ALSA tracks may have playback and capture capabilities. - * Here we model them as two separate GStreamer tracks. - */ - - for (i = 0; i < count; i++) { - GstMixerTrack *play_track = NULL; - GstMixerTrack *cap_track = NULL; - const gchar *name; - GList *item; - gint samename = 0; - - name = snd_mixer_selem_get_name (element); - - /* prevent dup names */ - for (item = mixer->tracklist; item != NULL; item = item->next) { - snd_mixer_elem_t *temp; - - if (GST_IS_ALSA_MIXER_OPTIONS (item->data)) - temp = GST_ALSA_MIXER_OPTIONS (item->data)->element; - else - temp = GST_ALSA_MIXER_TRACK (item->data)->element; - - if (strcmp (name, snd_mixer_selem_get_name (temp)) == 0) - samename++; - } - - GST_LOG ("[%s] probing element #%u, mixer->dir=%u", name, i, mixer->dir); - - if (mixer->dir & GST_ALSA_MIXER_PLAYBACK) { - gboolean has_playback_switch, has_playback_volume; - - has_playback_switch = snd_mixer_selem_has_playback_switch (element); - has_playback_volume = snd_mixer_selem_has_playback_volume (element); - - GST_LOG ("[%s] PLAYBACK: has_playback_volume=%d, has_playback_switch=%d" - "%s", name, has_playback_volume, has_playback_switch, - (element == master) ? " MASTER" : ""); - - if (has_playback_volume) { - gint flags = GST_MIXER_TRACK_OUTPUT; - - if (element == master) - flags |= GST_MIXER_TRACK_MASTER; - - play_track = gst_alsa_mixer_track_new (element, samename, i, - flags, FALSE, NULL, FALSE); - - } else if (has_playback_switch) { - /* simple mute switch */ - play_track = gst_alsa_mixer_track_new (element, samename, i, - GST_MIXER_TRACK_OUTPUT, TRUE, NULL, FALSE); - } - - if (snd_mixer_selem_is_enumerated (element)) { - GstMixerOptions *opts = gst_alsa_mixer_options_new (element, i); - - GST_LOG ("[%s] is enumerated (%d)", name, i); - mixer->tracklist = g_list_append (mixer->tracklist, opts); - } - } - - if (mixer->dir & GST_ALSA_MIXER_CAPTURE) { - gboolean has_capture_switch, has_common_switch; - gboolean has_capture_volume, has_common_volume; - - has_capture_switch = snd_mixer_selem_has_capture_switch (element); - has_common_switch = snd_mixer_selem_has_common_switch (element); - has_capture_volume = snd_mixer_selem_has_capture_volume (element); - has_common_volume = snd_mixer_selem_has_common_volume (element); - - GST_LOG ("[%s] CAPTURE: has_capture_volume=%d, has_common_volume=%d, " - "has_capture_switch=%d, has_common_switch=%d, play_track=%p", name, - has_capture_volume, has_common_volume, has_capture_switch, - has_common_switch, play_track); - - if (has_capture_volume && !(play_track && has_common_volume)) { - cap_track = gst_alsa_mixer_track_new (element, samename, i, - GST_MIXER_TRACK_INPUT, FALSE, NULL, play_track != NULL); - } else if (has_capture_switch && !(play_track && has_common_switch)) { - cap_track = gst_alsa_mixer_track_new (element, samename, i, - GST_MIXER_TRACK_INPUT, TRUE, NULL, play_track != NULL); - } - } - - - if (play_track && cap_track) { - GST_ALSA_MIXER_TRACK (play_track)->shared_mute = - GST_ALSA_MIXER_TRACK (cap_track); - GST_ALSA_MIXER_TRACK (cap_track)->shared_mute = - GST_ALSA_MIXER_TRACK (play_track); - } - - if (play_track) - mixer->tracklist = g_list_append (mixer->tracklist, play_track); - - if (cap_track) - mixer->tracklist = g_list_append (mixer->tracklist, cap_track); - - element = snd_mixer_elem_next (element); - } - - for (item = mixer->tracklist; item != NULL; item = item->next) { - snd_mixer_elem_t *temp; - - if (GST_IS_ALSA_MIXER_OPTIONS (item->data)) - temp = GST_ALSA_MIXER_OPTIONS (item->data)->element; - else - temp = GST_ALSA_MIXER_TRACK (item->data)->element; - - snd_mixer_elem_set_callback (temp, gst_alsa_mixer_elem_handle_callback); - snd_mixer_elem_set_callback_private (temp, mixer); - } - - g_static_rec_mutex_unlock (mixer->rec_mutex); -} - -static void -task_monitor_alsa (gpointer data) -{ - struct pollfd *pfds; - unsigned int nfds, rnfds; - unsigned short revents; - GstAlsaMixer *mixer = (GstAlsaMixer *) data; - - g_static_rec_mutex_lock (mixer->rec_mutex); - - nfds = snd_mixer_poll_descriptors_count (mixer->handle); - if (nfds <= 0) { - GST_ERROR ("snd_mixer_poll_descriptors_count <= 0: %d", nfds); - /* FIXME: sleep ? stop monitoring ? */ - return; - } - - pfds = g_newa (struct pollfd, nfds + 1); - rnfds = snd_mixer_poll_descriptors (mixer->handle, pfds, nfds); - g_assert (rnfds <= nfds); - - pfds[rnfds].fd = mixer->pfd[0]; - pfds[rnfds].events = POLLIN | POLLPRI | POLLHUP | POLLERR; - pfds[rnfds].revents = 0; - - g_static_rec_mutex_unlock (mixer->rec_mutex); - - GST_LOG ("task loop"); - poll (pfds, rnfds + 1, -1); - - g_static_rec_mutex_lock (mixer->rec_mutex); - - snd_mixer_poll_descriptors_revents (mixer->handle, pfds, nfds, &revents); - if (revents & POLLIN || revents & POLLPRI) { - GST_DEBUG ("Handling events"); - snd_mixer_handle_events (mixer->handle); - } - - g_static_rec_mutex_unlock (mixer->rec_mutex); -} - -/* API */ - -GstAlsaMixer * -gst_alsa_mixer_new (const char *device, GstAlsaMixerDirection dir) -{ - GstAlsaMixer *ret = NULL; - - g_return_val_if_fail (device != NULL, NULL); - - ret = g_new0 (GstAlsaMixer, 1); - - if (pipe (ret->pfd) == -1) - goto error; - - ret->rec_mutex = g_new (GStaticRecMutex, 1); - g_static_rec_mutex_init (ret->rec_mutex); - - ret->task_mutex = g_new (GStaticRecMutex, 1); - g_static_rec_mutex_init (ret->task_mutex); - - ret->task = gst_task_create (task_monitor_alsa, ret); - gst_task_set_lock (ret->task, ret->task_mutex); - - ret->device = g_strdup (device); - ret->dir = dir; - - if (!gst_alsa_mixer_open (ret)) - goto error; - - if (gst_task_start (ret->task) == FALSE) { - GST_WARNING ("Could not start alsamixer task"); - } - - return ret; - - /* ERRORS */ -error: - { - gst_alsa_mixer_free (ret); - return NULL; - } -} - -void -gst_alsa_mixer_free (GstAlsaMixer * mixer) -{ - g_return_if_fail (mixer != NULL); - - if (mixer->task) { - if (write (mixer->pfd[1], "stop", 5) <= 0) { - GST_ERROR ("Cannot send " "stop" " to alsamixer task"); - close (mixer->pfd[1]); - mixer->pfd[1] = -1; - } - - if (gst_task_join (mixer->task) == FALSE) { - GST_ERROR ("Cannot join alsamixer task"); - } - - gst_object_unref (mixer->task); - mixer->task = NULL; - } - - g_static_rec_mutex_free (mixer->task_mutex); - g_free (mixer->task_mutex); - mixer->task_mutex = NULL; - - if (mixer->pfd[0] > 0) { - close (mixer->pfd[0]); - mixer->pfd[0] = -1; - } - - if (mixer->pfd[1] > 0) { - close (mixer->pfd[1]); - mixer->pfd[1] = -1; - } - - if (mixer->interface) { - g_object_unref (G_OBJECT (mixer->interface)); - mixer->interface = NULL; - } - - if (mixer->device) { - g_free (mixer->device); - mixer->device = NULL; - } - - if (mixer->cardname) { - g_free (mixer->cardname); - mixer->cardname = NULL; - } - - if (mixer->tracklist) { - g_list_foreach (mixer->tracklist, (GFunc) g_object_unref, NULL); - g_list_free (mixer->tracklist); - mixer->tracklist = NULL; - } - - if (mixer->handle) { - snd_mixer_close (mixer->handle); - mixer->handle = NULL; - } - - g_static_rec_mutex_free (mixer->rec_mutex); - g_free (mixer->rec_mutex); - mixer->rec_mutex = NULL; - - g_free (mixer); -} - -const GList * -gst_alsa_mixer_list_tracks (GstAlsaMixer * mixer) -{ - g_return_val_if_fail (mixer->handle != NULL, NULL); - - gst_alsa_mixer_ensure_track_list (mixer); - - return (const GList *) mixer->tracklist; -} - -void -gst_alsa_mixer_get_volume (GstAlsaMixer * mixer, GstMixerTrack * track, - gint * volumes) -{ - gint i; - GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track); - - g_return_if_fail (mixer->handle != NULL); - - gst_alsa_mixer_track_update (alsa_track); - - if (track->flags & GST_MIXER_TRACK_OUTPUT) { /* return playback volume */ - - /* Is emulated mute flag activated? */ - if (track->flags & GST_MIXER_TRACK_MUTE && - !(alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PSWITCH)) { - for (i = 0; i < track->num_channels; i++) - volumes[i] = alsa_track->volumes[i]; - } else { - for (i = 0; i < track->num_channels; i++) { - long tmp = 0; - - snd_mixer_selem_get_playback_volume (alsa_track->element, i, &tmp); - alsa_track->volumes[i] = volumes[i] = (gint) tmp; - } - } - - } else if (track->flags & GST_MIXER_TRACK_INPUT) { /* return capture volume */ - - /* Is emulated record flag activated? */ - if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH || - track->flags & GST_MIXER_TRACK_RECORD) { - for (i = 0; i < track->num_channels; i++) { - long tmp = 0; - - snd_mixer_selem_get_capture_volume (alsa_track->element, i, &tmp); - alsa_track->volumes[i] = volumes[i] = (gint) tmp; - } - } else { - for (i = 0; i < track->num_channels; i++) - volumes[i] = alsa_track->volumes[i]; - } - } -} - -static gboolean -check_if_volumes_are_the_same (guint num_channels, gint * volumes) -{ - guint i; - - if (num_channels <= 1) - return TRUE; - - for (i = 1; i < num_channels; i++) { - if (volumes[i] != volumes[0]) - return FALSE; - } - - return TRUE; -} - -void -gst_alsa_mixer_set_volume (GstAlsaMixer * mixer, GstMixerTrack * track, - gint * volumes) -{ - GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track); - gint i; - - g_return_if_fail (mixer->handle != NULL); - - gst_alsa_mixer_track_update (alsa_track); - - if (track->flags & GST_MIXER_TRACK_OUTPUT) { - - /* Is emulated mute flag activated? */ - if (track->flags & GST_MIXER_TRACK_MUTE && - !(alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PSWITCH)) { - for (i = 0; i < track->num_channels; i++) - alsa_track->volumes[i] = volumes[i]; - } else { - if (check_if_volumes_are_the_same (track->num_channels, volumes)) { - snd_mixer_selem_set_playback_volume_all (alsa_track->element, - volumes[0]); - for (i = 0; i < track->num_channels; i++) - alsa_track->volumes[i] = volumes[0]; - } else { - for (i = 0; i < track->num_channels; i++) { - alsa_track->volumes[i] = volumes[i]; - snd_mixer_selem_set_playback_volume (alsa_track->element, i, - volumes[i]); - } - } - } - - } else if (track->flags & GST_MIXER_TRACK_INPUT) { - - /* Is emulated record flag activated? */ - if (track->flags & GST_MIXER_TRACK_RECORD || - alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH) { - if (check_if_volumes_are_the_same (track->num_channels, volumes)) { - snd_mixer_selem_set_capture_volume_all (alsa_track->element, - volumes[0]); - for (i = 0; i < track->num_channels; i++) - alsa_track->volumes[i] = volumes[0]; - } else { - for (i = 0; i < track->num_channels; i++) { - alsa_track->volumes[i] = volumes[i]; - snd_mixer_selem_set_capture_volume (alsa_track->element, i, - volumes[i]); - } - } - } else { - for (i = 0; i < track->num_channels; i++) - alsa_track->volumes[i] = volumes[i]; - } - } -} - -void -gst_alsa_mixer_set_mute (GstAlsaMixer * mixer, GstMixerTrack * track, - gboolean mute) -{ - GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track); - - g_return_if_fail (mixer->handle != NULL); - - gst_alsa_mixer_track_update (alsa_track); - - if (!!(mute) == !!(track->flags & GST_MIXER_TRACK_MUTE)) - return; - - if (mute) { - track->flags |= GST_MIXER_TRACK_MUTE; - - if (alsa_track->shared_mute) - ((GstMixerTrack *) (alsa_track->shared_mute))->flags |= - GST_MIXER_TRACK_MUTE; - } else { - track->flags &= ~GST_MIXER_TRACK_MUTE; - - if (alsa_track->shared_mute) - ((GstMixerTrack *) (alsa_track->shared_mute))->flags &= - ~GST_MIXER_TRACK_MUTE; - } - - if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PSWITCH) { - snd_mixer_selem_set_playback_switch_all (alsa_track->element, mute ? 0 : 1); - } else { - gint i; - GstAlsaMixerTrack *ctrl_track; - - if ((track->flags & GST_MIXER_TRACK_INPUT) - && alsa_track->shared_mute != NULL) - ctrl_track = alsa_track->shared_mute; - else - ctrl_track = alsa_track; - - for (i = 0; i < ((GstMixerTrack *) ctrl_track)->num_channels; i++) { - long vol = - mute ? ((GstMixerTrack *) ctrl_track)->min_volume : ctrl_track-> - volumes[i]; - snd_mixer_selem_set_playback_volume (ctrl_track->element, i, vol); - } - } -} - -void -gst_alsa_mixer_set_record (GstAlsaMixer * mixer, - GstMixerTrack * track, gboolean record) -{ - GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track); - - g_return_if_fail (mixer->handle != NULL); - - gst_alsa_mixer_track_update (alsa_track); - - if (!!(record) == !!(track->flags & GST_MIXER_TRACK_RECORD)) - return; - - if (record) { - track->flags |= GST_MIXER_TRACK_RECORD; - } else { - track->flags &= ~GST_MIXER_TRACK_RECORD; - } - - if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH) { - snd_mixer_selem_set_capture_switch_all (alsa_track->element, - record ? 1 : 0); - - /* update all tracks in same exlusive cswitch group */ - if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH_EXCL) { - GList *item; - - for (item = mixer->tracklist; item != NULL; item = item->next) { - - if (GST_IS_ALSA_MIXER_TRACK (item->data)) { - GstAlsaMixerTrack *item_alsa_track = - GST_ALSA_MIXER_TRACK (item->data); - - if (item_alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH_EXCL && - item_alsa_track->capture_group == alsa_track->capture_group) { - gst_alsa_mixer_track_update (item_alsa_track); - } - } - } - } - } else { - gint i; - - for (i = 0; i < track->num_channels; i++) { - long vol = record ? alsa_track->volumes[i] : track->min_volume; - - snd_mixer_selem_set_capture_volume (alsa_track->element, i, vol); - } - } -} - -void -gst_alsa_mixer_set_option (GstAlsaMixer * mixer, - GstMixerOptions * opts, gchar * value) -{ - gint idx = -1, n = 0; - GList *item; - GstAlsaMixerOptions *alsa_opts = GST_ALSA_MIXER_OPTIONS (opts); - - g_return_if_fail (mixer->handle != NULL); - - for (item = opts->values; item != NULL; item = item->next, n++) { - if (!strcmp (item->data, value)) { - idx = n; - break; - } - } - if (idx == -1) - return; - - snd_mixer_selem_set_enum_item (alsa_opts->element, 0, idx); -} - -const gchar * -gst_alsa_mixer_get_option (GstAlsaMixer * mixer, GstMixerOptions * opts) -{ - gint ret; - guint idx; - GstAlsaMixerOptions *alsa_opts = GST_ALSA_MIXER_OPTIONS (opts); - - g_return_val_if_fail (mixer->handle != NULL, NULL); - - ret = snd_mixer_selem_get_enum_item (alsa_opts->element, 0, &idx); - if (ret == 0) - return g_list_nth_data (opts->values, idx); - else - return snd_strerror (ret); /* feeble attempt at error handling */ -} - -GstMixerFlags -gst_alsa_mixer_get_mixer_flags (GstAlsaMixer * mixer) -{ - g_return_val_if_fail (mixer != NULL, GST_MIXER_FLAG_NONE); - - return GST_MIXER_FLAG_AUTO_NOTIFICATIONS; -} - -static void -gst_alsa_mixer_update_option (GstAlsaMixer * mixer, - GstAlsaMixerOptions * alsa_opts) -{ - gint ret; - guint idx; - /* const */ gchar *option; - - if (mixer->interface == NULL) { - GST_WARNING ("Cannot send update notifications, no GstMixer * given"); - return; - } - - ret = snd_mixer_selem_get_enum_item (alsa_opts->element, 0, &idx); - if (ret == 0) { - option = g_list_nth_data (GST_MIXER_OPTIONS (alsa_opts)->values, idx); - gst_mixer_option_changed (mixer->interface, GST_MIXER_OPTIONS (alsa_opts), - option); - } -} - -static void -gst_alsa_mixer_update_track (GstAlsaMixer * mixer, - GstAlsaMixerTrack * alsa_track) -{ - GstMixerTrack *track = (GstMixerTrack *) alsa_track; - gboolean old_mute; - gboolean old_record; - gint i, n_channels; - gint *old_volumes; - - GST_DEBUG ("Updating track %" GST_PTR_FORMAT, alsa_track); - - if (mixer->interface == NULL) { - GST_WARNING ("Cannot send update notifications, no GstMixer * given"); - return; - } - - old_mute = !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE)); - old_record = !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)); - old_volumes = g_new (gint, track->num_channels); - n_channels = track->num_channels; - memcpy (old_volumes, alsa_track->volumes, - sizeof (gint) * track->num_channels); - - gst_alsa_mixer_track_update (alsa_track); - - if (old_record != - !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD))) { - gst_mixer_record_toggled (mixer->interface, track, - !!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)); - } - if (old_mute != !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE))) { - gst_mixer_mute_toggled (mixer->interface, track, - !!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE)); - } - - n_channels = MIN (n_channels, track->num_channels); - for (i = 0; i < n_channels; i++) { - if (old_volumes[i] != alsa_track->volumes[i]) { - gst_mixer_volume_changed (mixer->interface, track, alsa_track->volumes); - break; - } - } - g_free (old_volumes); -} - -/* utility function for gstalsamixerelement to set the interface */ -void -_gst_alsa_mixer_set_interface (GstAlsaMixer * mixer, GstMixer * interface) -{ - g_return_if_fail (mixer != NULL && mixer->interface == NULL); - g_return_if_fail (interface != NULL); - - mixer->interface = g_object_ref (G_OBJECT (interface)); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsamixer.h --- a/gst_plugins_base/ext/alsa/gstalsamixer.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,217 +0,0 @@ -/* ALSA mixer interface implementation. - * Copyright (C) 2003 Leif Johnson - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#ifndef __GST_ALSA_MIXER_H__ -#define __GST_ALSA_MIXER_H__ - - -#include "gstalsa.h" - -#include -#include "gstalsamixeroptions.h" -#include "gstalsamixertrack.h" - - -G_BEGIN_DECLS - -/* This does not get you what you think it does, use obj->mixer */ -/* #define GST_ALSA_MIXER(obj) ((GstAlsaMixer*)(obj)) */ - -typedef struct _GstAlsaMixer GstAlsaMixer; - -typedef enum { - GST_ALSA_MIXER_CAPTURE = 1<<0, - GST_ALSA_MIXER_PLAYBACK = 1<<1, - GST_ALSA_MIXER_ALL = GST_ALSA_MIXER_CAPTURE | GST_ALSA_MIXER_PLAYBACK -} GstAlsaMixerDirection; - -/** - * GstAlsaMixer: - * - * Opaque data structure - */ -struct _GstAlsaMixer -{ - GList * tracklist; /* list of available tracks */ - - snd_mixer_t * handle; - - GstTask * task; - GStaticRecMutex * task_mutex; - GStaticRecMutex * rec_mutex; - - int pfd[2]; - - GstMixer * interface; - gchar * device; - gchar * cardname; - - GstAlsaMixerDirection dir; -}; - - -GstAlsaMixer* gst_alsa_mixer_new (const gchar *device, - GstAlsaMixerDirection dir); -void gst_alsa_mixer_free (GstAlsaMixer *mixer); - -const GList* gst_alsa_mixer_list_tracks (GstAlsaMixer * mixer); -void gst_alsa_mixer_set_volume (GstAlsaMixer * mixer, - GstMixerTrack * track, - gint * volumes); -void gst_alsa_mixer_get_volume (GstAlsaMixer * mixer, - GstMixerTrack * track, - gint * volumes); -void gst_alsa_mixer_set_record (GstAlsaMixer * mixer, - GstMixerTrack * track, - gboolean record); -void gst_alsa_mixer_set_mute (GstAlsaMixer * mixer, - GstMixerTrack * track, - gboolean mute); -void gst_alsa_mixer_set_option (GstAlsaMixer * mixer, - GstMixerOptions * opts, - gchar * value); -const gchar* gst_alsa_mixer_get_option (GstAlsaMixer * mixer, - GstMixerOptions * opts); -void _gst_alsa_mixer_set_interface (GstAlsaMixer * mixer, - GstMixer * interface); -GstMixerFlags gst_alsa_mixer_get_mixer_flags (GstAlsaMixer *mixer); - -#define GST_IMPLEMENT_ALSA_MIXER_METHODS(Type, interface_as_function) \ -static gboolean \ -interface_as_function ## _supported (Type *this, GType iface_type) \ -{ \ - g_assert (iface_type == GST_TYPE_MIXER); \ - \ - return (this->mixer != NULL); \ -} \ - \ -static const GList* \ -interface_as_function ## _list_tracks (GstMixer * mixer) \ -{ \ - Type *this = (Type*) mixer; \ - \ - g_return_val_if_fail (this != NULL, NULL); \ - g_return_val_if_fail (this->mixer != NULL, NULL); \ - \ - return gst_alsa_mixer_list_tracks (this->mixer); \ -} \ - \ -static void \ -interface_as_function ## _set_volume (GstMixer * mixer, GstMixerTrack * track, \ - gint * volumes) \ -{ \ - Type *this = (Type*) mixer; \ - \ - g_return_if_fail (this != NULL); \ - g_return_if_fail (this->mixer != NULL); \ - \ - gst_alsa_mixer_set_volume (this->mixer, track, volumes); \ -} \ - \ -static void \ -interface_as_function ## _get_volume (GstMixer * mixer, GstMixerTrack * track, \ - gint * volumes) \ -{ \ - Type *this = (Type*) mixer; \ - \ - g_return_if_fail (this != NULL); \ - g_return_if_fail (this->mixer != NULL); \ - \ - gst_alsa_mixer_get_volume (this->mixer, track, volumes); \ -} \ - \ -static void \ -interface_as_function ## _set_record (GstMixer * mixer, GstMixerTrack * track, \ - gboolean record) \ -{ \ - Type *this = (Type*) mixer; \ - \ - g_return_if_fail (this != NULL); \ - g_return_if_fail (this->mixer != NULL); \ - \ - gst_alsa_mixer_set_record (this->mixer, track, record); \ -} \ - \ -static void \ -interface_as_function ## _set_mute (GstMixer * mixer, GstMixerTrack * track, \ - gboolean mute) \ -{ \ - Type *this = (Type*) mixer; \ - \ - g_return_if_fail (this != NULL); \ - g_return_if_fail (this->mixer != NULL); \ - \ - gst_alsa_mixer_set_mute (this->mixer, track, mute); \ -} \ - \ -static void \ -interface_as_function ## _set_option (GstMixer * mixer, GstMixerOptions * opts, \ - gchar * value) \ -{ \ - Type *this = (Type*) mixer; \ - \ - g_return_if_fail (this != NULL); \ - g_return_if_fail (this->mixer != NULL); \ - \ - gst_alsa_mixer_set_option (this->mixer, opts, value); \ -} \ - \ -static const gchar* \ -interface_as_function ## _get_option (GstMixer * mixer, GstMixerOptions * opts) \ -{ \ - Type *this = (Type*) mixer; \ - \ - g_return_val_if_fail (this != NULL, NULL); \ - g_return_val_if_fail (this->mixer != NULL, NULL); \ - \ - return gst_alsa_mixer_get_option (this->mixer, opts); \ -} \ - \ -static GstMixerFlags \ -interface_as_function ## _get_mixer_flags (GstMixer * mixer) \ -{ \ - Type *this = (Type*) mixer; \ - \ - g_return_val_if_fail (this != NULL, GST_MIXER_FLAG_NONE); \ - g_return_val_if_fail (this->mixer != NULL, GST_MIXER_FLAG_NONE); \ - \ - return gst_alsa_mixer_get_mixer_flags (this->mixer); \ -} \ - \ -static void \ -interface_as_function ## _interface_init (GstMixerClass * klass) \ -{ \ - GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; \ - \ - /* set up the interface hooks */ \ - klass->list_tracks = interface_as_function ## _list_tracks; \ - klass->set_volume = interface_as_function ## _set_volume; \ - klass->get_volume = interface_as_function ## _get_volume; \ - klass->set_mute = interface_as_function ## _set_mute; \ - klass->set_record = interface_as_function ## _set_record; \ - klass->set_option = interface_as_function ## _set_option; \ - klass->get_option = interface_as_function ## _get_option; \ - klass->get_mixer_flags = interface_as_function ## _get_mixer_flags; \ -} - - -G_END_DECLS - - -#endif /* __GST_ALSA_MIXER_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsamixerelement.c --- a/gst_plugins_base/ext/alsa/gstalsamixerelement.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,248 +0,0 @@ -/* ALSA mixer implementation. - * Copyright (C) 2003 Leif Johnson - * - * 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. - */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstalsamixerelement.h" -#include "gstalsadeviceprobe.h" - -#define DEFAULT_PROP_DEVICE "default" -#define DEFAULT_PROP_DEVICE_NAME "" - -enum -{ - PROP_0, - PROP_DEVICE, - PROP_DEVICE_NAME -}; - -static const GstElementDetails gst_alsa_mixer_element_details = -GST_ELEMENT_DETAILS ("Alsa mixer", - "Generic/Audio", - "Control sound input and output levels with ALSA", - "Leif Johnson "); - -static void gst_alsa_mixer_element_init_interfaces (GType type); - -GST_BOILERPLATE_FULL (GstAlsaMixerElement, gst_alsa_mixer_element, - GstElement, GST_TYPE_ELEMENT, gst_alsa_mixer_element_init_interfaces); - -/* massive macro that takes care of all the GstMixer stuff */ -GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaMixerElement, gst_alsa_mixer_element); - -static void gst_alsa_mixer_element_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_alsa_mixer_element_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_alsa_mixer_element_finalize (GObject * object); - -static GstStateChangeReturn gst_alsa_mixer_element_change_state (GstElement - * element, GstStateChange transition); - -static gboolean -gst_alsa_mixer_element_interface_supported (GstAlsaMixerElement * this, - GType interface_type) -{ - if (interface_type == GST_TYPE_MIXER) { - return gst_alsa_mixer_element_supported (this, interface_type); - } - - g_return_val_if_reached (FALSE); -} - -static void -gst_implements_interface_init (GstImplementsInterfaceClass * klass) -{ - klass->supported = (gpointer) gst_alsa_mixer_element_interface_supported; -} - -static void -gst_alsa_mixer_element_init_interfaces (GType type) -{ - static const GInterfaceInfo implements_iface_info = { - (GInterfaceInitFunc) gst_implements_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo mixer_iface_info = { - (GInterfaceInitFunc) gst_alsa_mixer_element_interface_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, - &implements_iface_info); - g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info); - - gst_alsa_type_add_device_property_probe_interface (type); -} - -static void -gst_alsa_mixer_element_base_init (gpointer klass) -{ - gst_element_class_set_details (GST_ELEMENT_CLASS (klass), - &gst_alsa_mixer_element_details); -} - -static void -gst_alsa_mixer_element_class_init (GstAlsaMixerElementClass * klass) -{ - GstElementClass *element_class; - GObjectClass *gobject_class; - - element_class = (GstElementClass *) klass; - gobject_class = (GObjectClass *) klass; - - gobject_class->finalize = gst_alsa_mixer_element_finalize; - gobject_class->get_property = gst_alsa_mixer_element_get_property; - gobject_class->set_property = gst_alsa_mixer_element_set_property; - - g_object_class_install_property (gobject_class, PROP_DEVICE, - g_param_spec_string ("device", "Device", - "ALSA device, as defined in an asound configuration file", - DEFAULT_PROP_DEVICE, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_DEVICE_NAME, - g_param_spec_string ("device-name", "Device name", - "Human-readable name of the sound device", - DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE)); - - element_class->change_state = - GST_DEBUG_FUNCPTR (gst_alsa_mixer_element_change_state); -} - -static void -gst_alsa_mixer_element_finalize (GObject * obj) -{ - GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (obj); - - g_free (this->device); - - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static void -gst_alsa_mixer_element_init (GstAlsaMixerElement * this, - GstAlsaMixerElementClass * klass) -{ - this->mixer = NULL; - this->device = g_strdup (DEFAULT_PROP_DEVICE); -} - -static void -gst_alsa_mixer_element_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (object); - - switch (prop_id) { - case PROP_DEVICE:{ - GST_OBJECT_LOCK (this); - g_free (this->device); - this->device = g_value_dup_string (value); - /* make sure we never set NULL, this is nice when we want to open the - * device. */ - if (this->device == NULL) - this->device = g_strdup (DEFAULT_PROP_DEVICE); - GST_OBJECT_UNLOCK (this); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_alsa_mixer_element_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (object); - - switch (prop_id) { - case PROP_DEVICE:{ - GST_OBJECT_LOCK (this); - g_value_set_string (value, this->device); - GST_OBJECT_UNLOCK (this); - break; - } - case PROP_DEVICE_NAME:{ - GST_OBJECT_LOCK (this); - if (this->mixer) { - g_value_set_string (value, this->mixer->cardname); - } else { - g_value_set_string (value, NULL); - } - GST_OBJECT_UNLOCK (this); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_alsa_mixer_element_change_state (GstElement * element, - GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!this->mixer) { - this->mixer = gst_alsa_mixer_new (this->device, GST_ALSA_MIXER_ALL); - if (!this->mixer) - goto open_failed; - _gst_alsa_mixer_set_interface (this->mixer, GST_MIXER (element)); - } - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - if (this->mixer) { - gst_alsa_mixer_free (this->mixer); - this->mixer = NULL; - } - break; - default: - break; - } - - return ret; - - /* ERRORS */ -open_failed: - { - GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ_WRITE, (NULL), - ("Failed to open alsa mixer device '%s'", this->device)); - return GST_STATE_CHANGE_FAILURE; - } -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsamixerelement.h --- a/gst_plugins_base/ext/alsa/gstalsamixerelement.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* ALSA mixer interface implementation. - * Copyright (C) 2003 Leif Johnson - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#ifndef __GST_ALSA_MIXER_ELEMENT_H__ -#define __GST_ALSA_MIXER_ELEMENT_H__ - - -#include "gstalsa.h" -#include "gstalsamixer.h" - -G_BEGIN_DECLS - -#define GST_ALSA_MIXER_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_MIXER_ELEMENT,GstAlsaMixerElement)) -#define GST_ALSA_MIXER_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_MIXER_ELEMENT,GstAlsaMixerElementClass)) -#define GST_IS_ALSA_MIXER_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_MIXER_ELEMENT)) -#define GST_IS_ALSA_MIXER_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_MIXER_ELEMENT)) -#define GST_TYPE_ALSA_MIXER_ELEMENT (gst_alsa_mixer_element_get_type()) - -typedef struct _GstAlsaMixerElement GstAlsaMixerElement; -typedef struct _GstAlsaMixerElementClass GstAlsaMixerElementClass; - -/** - * GstAlsaMixerElement - * - * Opaque datastructure. - */ -struct _GstAlsaMixerElement { - GstElement parent; - - GstAlsaMixer *mixer; - gchar *device; -}; - -struct _GstAlsaMixerElementClass { - GstElementClass parent; -}; - - -GType gst_alsa_mixer_element_get_type (void); - - -G_END_DECLS - - -#endif /* __GST_ALSA_MIXER_ELEMENT_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsamixeroptions.c --- a/gst_plugins_base/ext/alsa/gstalsamixeroptions.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* ALSA mixer object implementation. - * Copyright (C) 2003 Leif Johnson - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstalsamixeroptions.h" - -static void gst_alsa_mixer_options_init (GstAlsaMixerOptions * alsa_opts); -static void gst_alsa_mixer_options_class_init (gpointer g_class, - gpointer class_data); - -static GstMixerOptionsClass *parent_class = NULL; - -GType -gst_alsa_mixer_options_get_type (void) -{ - static GType opts_type = 0; - - if (!opts_type) { - static const GTypeInfo opts_info = { - sizeof (GstAlsaMixerOptionsClass), - NULL, - NULL, - gst_alsa_mixer_options_class_init, - NULL, - NULL, - sizeof (GstAlsaMixerOptions), - 0, - (GInstanceInitFunc) gst_alsa_mixer_options_init, - }; - - opts_type = - g_type_register_static (GST_TYPE_MIXER_OPTIONS, "GstAlsaMixerOptions", - &opts_info, 0); - } - - return opts_type; -} - -static void -gst_alsa_mixer_options_class_init (gpointer g_class, gpointer class_data) -{ - parent_class = g_type_class_peek_parent (g_class); -} - -static void -gst_alsa_mixer_options_init (GstAlsaMixerOptions * alsa_opts) -{ -} - -GstMixerOptions * -gst_alsa_mixer_options_new (snd_mixer_elem_t * element, gint track_num) -{ - GstMixerOptions *opts; - GstAlsaMixerOptions *alsa_opts; - GstMixerTrack *track; - const gchar *label; - gint num, i; - gchar str[256]; - - label = snd_mixer_selem_get_name (element); - - opts = g_object_new (GST_ALSA_MIXER_OPTIONS_TYPE, - "untranslated-label", label, NULL); - alsa_opts = (GstAlsaMixerOptions *) opts; - track = (GstMixerTrack *) opts; - - /* set basic information */ - track->label = g_strdup (label); /* FIXME: translate this? */ - track->num_channels = 0; - track->flags = 0; - alsa_opts->element = element; - alsa_opts->track_num = track_num; - - /* get enumerations for switch/options object */ - num = snd_mixer_selem_get_enum_items (element); - for (i = 0; i < num; i++) { - if (snd_mixer_selem_get_enum_item_name (element, i, 255, str) < 0) { - g_object_unref (G_OBJECT (alsa_opts)); - return NULL; - } - - opts->values = g_list_append (opts->values, g_strdup (str)); - } - - return opts; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsamixeroptions.h --- a/gst_plugins_base/ext/alsa/gstalsamixeroptions.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* ALSA mixer options object. - * Copyright (C) 2003 Leif Johnson - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#ifndef __GST_ALSA_MIXER_OPTIONS_H__ -#define __GST_ALSA_MIXER_OPTIONS_H__ - - -#include "gstalsa.h" -#include - - -G_BEGIN_DECLS - - -#define GST_ALSA_MIXER_OPTIONS_TYPE (gst_alsa_mixer_options_get_type ()) -#define GST_ALSA_MIXER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_MIXER_OPTIONS,GstAlsaMixerOptions)) -#define GST_ALSA_MIXER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_MIXER_OPTIONS,GstAlsaMixerOptionsClass)) -#define GST_IS_ALSA_MIXER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_MIXER_OPTIONS)) -#define GST_IS_ALSA_MIXER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_MIXER_OPTIONS)) -#define GST_TYPE_ALSA_MIXER_OPTIONS (gst_alsa_mixer_options_get_type()) - - -typedef struct _GstAlsaMixerOptions GstAlsaMixerOptions; -typedef struct _GstAlsaMixerOptionsClass GstAlsaMixerOptionsClass; - - -struct _GstAlsaMixerOptions { - GstMixerOptions parent; - snd_mixer_elem_t *element; /* the ALSA mixer element for this track */ - gint track_num; -}; - -struct _GstAlsaMixerOptionsClass { - GstMixerOptionsClass parent; -}; - - -GType gst_alsa_mixer_options_get_type (void); -GstMixerOptions *gst_alsa_mixer_options_new (snd_mixer_elem_t * element, - gint track_num); - - -G_END_DECLS - - -#endif /* __GST_ALSA_MIXER_OPTIONS_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsamixertrack.c --- a/gst_plugins_base/ext/alsa/gstalsamixertrack.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,339 +0,0 @@ -/* ALSA mixer track implementation. - * Copyright (C) 2003 Leif Johnson - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "gstalsamixertrack.h" - -static void gst_alsa_mixer_track_init (GstAlsaMixerTrack * alsa_track); -static void gst_alsa_mixer_track_class_init (gpointer g_class, - gpointer class_data); - -static GstMixerTrackClass *parent_class = NULL; - -GType -gst_alsa_mixer_track_get_type (void) -{ - static GType track_type = 0; - - if (!track_type) { - static const GTypeInfo track_info = { - sizeof (GstAlsaMixerTrackClass), - NULL, - NULL, - gst_alsa_mixer_track_class_init, - NULL, - NULL, - sizeof (GstAlsaMixerTrack), - 0, - (GInstanceInitFunc) gst_alsa_mixer_track_init, - NULL - }; - - track_type = - g_type_register_static (GST_TYPE_MIXER_TRACK, "GstAlsaMixerTrack", - &track_info, 0); - } - - return track_type; -} - -static void -gst_alsa_mixer_track_class_init (gpointer g_class, gpointer class_data) -{ - parent_class = g_type_class_peek_parent (g_class); -} - -static void -gst_alsa_mixer_track_init (GstAlsaMixerTrack * alsa_track) -{ -} - -static void -gst_alsa_mixer_track_update_alsa_capabilities (GstAlsaMixerTrack * alsa_track) -{ - alsa_track->alsa_flags = 0; - alsa_track->capture_group = -1; - - if (snd_mixer_selem_has_common_volume (alsa_track->element)) - alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_VOLUME; - - if (snd_mixer_selem_has_playback_volume (alsa_track->element)) - alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PVOLUME; - - if (snd_mixer_selem_has_capture_volume (alsa_track->element)) - alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CVOLUME; - - if (snd_mixer_selem_has_common_switch (alsa_track->element)) - alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_SWITCH; - - if (snd_mixer_selem_has_playback_switch (alsa_track->element)) - alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PSWITCH; - - if (snd_mixer_selem_has_capture_switch (alsa_track->element)) { - alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH; - - if (snd_mixer_selem_has_capture_switch_exclusive (alsa_track->element)) { - alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH_EXCL; - alsa_track->capture_group = - snd_mixer_selem_get_capture_group (alsa_track->element); - } - } - - GST_LOG ("[%s] alsa_flags=0x%08x, capture_group=%d", - snd_mixer_selem_get_name (alsa_track->element), - alsa_track->alsa_flags, alsa_track->capture_group); -} - -inline static gboolean -alsa_track_has_cap (GstAlsaMixerTrack * alsa_track, guint32 flag) -{ - return ((alsa_track->alsa_flags & flag) != 0); -} - -GstMixerTrack * -gst_alsa_mixer_track_new (snd_mixer_elem_t * element, - gint num, gint track_num, gint flags, gboolean sw, - GstAlsaMixerTrack * shared_mute_track, gboolean append_capture) -{ - GstAlsaMixerTrack *alsa_track; - GstMixerTrack *track; - const gchar *name; - const gchar *label; - gint i; - long min = 0, max = 0; - const struct - { - const gchar orig[12]; - const gchar trans[12]; - } alsa_track_labels[] = { - { - "Master", N_("Master")}, { - "Bass", N_("Bass")}, { - "Treble", N_("Treble")}, { - "PCM", N_("PCM")}, { - "Synth", N_("Synth")}, { - "Line", N_("Line-in")}, { - "CD", N_("CD")}, { - "Mic", N_("Microphone")}, { - "PC Speaker", N_("PC Speaker")}, { - "Playback", N_("Playback")}, { - "Capture", N_("Capture")} - }; - - name = snd_mixer_selem_get_name (element); - - GST_LOG ("[%s] num=%d,track_num=%d,flags=0x%08x,sw=%s,shared_mute_track=%p", - name, num, track_num, flags, (sw) ? "true" : "false", shared_mute_track); - - track = (GstMixerTrack *) g_object_new (GST_ALSA_MIXER_TRACK_TYPE, - "untranslated-label", name, NULL); - - alsa_track = (GstAlsaMixerTrack *) track; - - GST_LOG ("[%s] created new mixer track %p", name, track); - - /* This reflects the assumptions used for GstAlsaMixerTrack */ - if (!(!!(flags & GST_MIXER_TRACK_OUTPUT) ^ !!(flags & GST_MIXER_TRACK_INPUT))) { - GST_ERROR ("Mixer track must be either output or input!"); - g_return_val_if_reached (NULL); - } - - track->flags = flags; - alsa_track->element = element; - alsa_track->shared_mute = shared_mute_track; - alsa_track->track_num = track_num; - alsa_track->alsa_channels = 0; - - gst_alsa_mixer_track_update_alsa_capabilities (alsa_track); - - if (flags & GST_MIXER_TRACK_OUTPUT) { - while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS && - snd_mixer_selem_has_playback_channel (element, - alsa_track->alsa_channels)) { - alsa_track->alsa_channels++; - } - GST_LOG ("[%s] %d output channels", name, alsa_track->alsa_channels); - } else if (flags & GST_MIXER_TRACK_INPUT) { - while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS && - snd_mixer_selem_has_capture_channel (element, - alsa_track->alsa_channels)) { - alsa_track->alsa_channels++; - } - GST_LOG ("[%s] %d input channels", name, alsa_track->alsa_channels); - } else { - g_assert_not_reached (); - } - - if (sw) - track->num_channels = 0; - else - track->num_channels = alsa_track->alsa_channels; - - /* translate the name if we can */ - label = name; - for (i = 0; i < G_N_ELEMENTS (alsa_track_labels); ++i) { - if (g_utf8_collate (label, alsa_track_labels[i].orig) == 0) { - label = _(alsa_track_labels[i].trans); - break; - } - } - - if (num == 0) { - track->label = g_strdup_printf ("%s%s%s", label, - append_capture ? " " : "", append_capture ? _("Capture") : ""); - } else { - track->label = g_strdup_printf ("%s%s%s %d", label, - append_capture ? " " : "", append_capture ? _("Capture") : "", num); - } - - /* set volume information */ - if (track->num_channels > 0) { - if ((flags & GST_MIXER_TRACK_OUTPUT)) - snd_mixer_selem_get_playback_volume_range (element, &min, &max); - else - snd_mixer_selem_get_capture_volume_range (element, &min, &max); - } - track->min_volume = (gint) min; - track->max_volume = (gint) max; - - for (i = 0; i < track->num_channels; i++) { - long tmp = 0; - - if (flags & GST_MIXER_TRACK_OUTPUT) - snd_mixer_selem_get_playback_volume (element, i, &tmp); - else - snd_mixer_selem_get_capture_volume (element, i, &tmp); - - alsa_track->volumes[i] = (gint) tmp; - } - - gst_alsa_mixer_track_update (alsa_track); - - return track; -} - -void -gst_alsa_mixer_track_update (GstAlsaMixerTrack * alsa_track) -{ - GstMixerTrack *track = (GstMixerTrack *) alsa_track; - gint i; - gint audible = !(track->flags & GST_MIXER_TRACK_MUTE); - - if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME)) { - /* update playback volume */ - for (i = 0; i < track->num_channels; i++) { - long vol = 0; - - snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol); - alsa_track->volumes[i] = (gint) vol; - } - } - - if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME)) { - /* update capture volume */ - for (i = 0; i < track->num_channels; i++) { - long vol = 0; - - snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol); - alsa_track->volumes[i] = (gint) vol; - } - } - - /* Any updates in flags? */ - if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PSWITCH)) { - int v = 0; - - audible = 0; - for (i = 0; i < alsa_track->alsa_channels; ++i) { - snd_mixer_selem_get_playback_switch (alsa_track->element, i, &v); - audible += v; - } - - } else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME) && - track->flags & GST_MIXER_TRACK_MUTE) { - /* check if user has raised volume with a parallel running application */ - - for (i = 0; i < track->num_channels; i++) { - long vol = 0; - - snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol); - - if (vol > track->min_volume) { - audible = 1; - break; - } - } - } - - if (!!(audible) != !(track->flags & GST_MIXER_TRACK_MUTE)) { - if (audible) { - track->flags &= ~GST_MIXER_TRACK_MUTE; - - if (alsa_track->shared_mute) - ((GstMixerTrack *) (alsa_track->shared_mute))->flags &= - ~GST_MIXER_TRACK_MUTE; - } else { - track->flags |= GST_MIXER_TRACK_MUTE; - - if (alsa_track->shared_mute) - ((GstMixerTrack *) (alsa_track->shared_mute))->flags |= - GST_MIXER_TRACK_MUTE; - } - } - - if (track->flags & GST_MIXER_TRACK_INPUT) { - gint recording = track->flags & GST_MIXER_TRACK_RECORD; - - if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CSWITCH)) { - int v = 0; - - recording = 0; - for (i = 0; i < alsa_track->alsa_channels; ++i) { - snd_mixer_selem_get_capture_switch (alsa_track->element, i, &v); - recording += v; - } - - } else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME) && - !(track->flags & GST_MIXER_TRACK_RECORD)) { - /* check if user has raised volume with a parallel running application */ - - for (i = 0; i < track->num_channels; i++) { - long vol = 0; - - snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol); - - if (vol > track->min_volume) { - recording = 1; - break; - } - } - } - - if (recording) - track->flags |= GST_MIXER_TRACK_RECORD; - else - track->flags &= ~GST_MIXER_TRACK_RECORD; - } - -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsamixertrack.h --- a/gst_plugins_base/ext/alsa/gstalsamixertrack.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* ALSA mixer track object. - * Copyright (C) 2003 Leif Johnson - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#ifndef __GST_ALSA_MIXER_TRACK_H__ -#define __GST_ALSA_MIXER_TRACK_H__ - - -#include "gstalsa.h" -#include - - -G_BEGIN_DECLS - - -#define GST_ALSA_MIXER_TRACK_TYPE (gst_alsa_mixer_track_get_type ()) -#define GST_ALSA_MIXER_TRACK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_MIXER_TRACK,GstAlsaMixerTrack)) -#define GST_ALSA_MIXER_TRACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_MIXER_TRACK,GstAlsaMixerTrackClass)) -#define GST_IS_ALSA_MIXER_TRACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_MIXER_TRACK)) -#define GST_IS_ALSA_MIXER_TRACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_MIXER_TRACK)) -#define GST_TYPE_ALSA_MIXER_TRACK (gst_alsa_mixer_track_get_type()) - -typedef struct _GstAlsaMixerTrack GstAlsaMixerTrack; -typedef struct _GstAlsaMixerTrackClass GstAlsaMixerTrackClass; - -#define GST_ALSA_MIXER_TRACK_VOLUME (1<<0) /* common volume */ -#define GST_ALSA_MIXER_TRACK_PVOLUME (1<<1) -#define GST_ALSA_MIXER_TRACK_CVOLUME (1<<2) -#define GST_ALSA_MIXER_TRACK_SWITCH (1<<3) /* common switch */ -#define GST_ALSA_MIXER_TRACK_PSWITCH (1<<4) -#define GST_ALSA_MIXER_TRACK_CSWITCH (1<<5) -#define GST_ALSA_MIXER_TRACK_CSWITCH_EXCL (1<<6) - -#define GST_ALSA_MAX_CHANNELS (SND_MIXER_SCHN_LAST+1) - -struct _GstAlsaMixerTrack { - GstMixerTrack parent; - snd_mixer_elem_t *element; /* the ALSA mixer element for this track */ - GstAlsaMixerTrack *shared_mute; - gint track_num; - guint32 alsa_flags; /* alsa track capabilities */ - gint alsa_channels; - gint capture_group; - gint volumes[GST_ALSA_MAX_CHANNELS]; -}; - -struct _GstAlsaMixerTrackClass { - GstMixerTrackClass parent; -}; - -GType gst_alsa_mixer_track_get_type (void); -GstMixerTrack * gst_alsa_mixer_track_new (snd_mixer_elem_t * element, - gint num, - gint track_num, - gint flags, - gboolean sw, /* is simple switch? */ - GstAlsaMixerTrack * shared_mute_track, - gboolean label_append_capture); -void gst_alsa_mixer_track_update (GstAlsaMixerTrack * alsa_track); - -G_END_DECLS - - -#endif /* __GST_ALSA_MIXER_TRACK_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsaplugin.c --- a/gst_plugins_base/ext/alsa/gstalsaplugin.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2001 CodeFactory AB - * Copyright (C) 2001 Thomas Nyberg - * Copyright (C) 2001-2002 Andy Wingo - * Copyright (C) 2003 Benjamin Otte - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstalsasink.h" -#include "gstalsasrc.h" -#include "gstalsamixerelement.h" - -#include - -GST_DEBUG_CATEGORY (alsa_debug); - -/* ALSA debugging wrapper */ -static void -gst_alsa_error_wrapper (const char *file, int line, const char *function, - int err, const char *fmt, ...) -{ -#ifndef GST_DISABLE_GST_DEBUG - va_list args; - gchar *str; - - va_start (args, fmt); - str = g_strdup_vprintf (fmt, args); - va_end (args); - /* FIXME: use GST_LEVEL_ERROR here? Currently warning is used because we're - * able to catch enough of the errors that would be printed otherwise - */ - gst_debug_log (alsa_debug, GST_LEVEL_WARNING, file, function, line, NULL, - "alsalib error: %s%s%s", str, err ? ": " : "", - err ? snd_strerror (err) : ""); - g_free (str); -#endif -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - int err; - - if (!gst_element_register (plugin, "alsamixer", GST_RANK_NONE, - GST_TYPE_ALSA_MIXER_ELEMENT)) - return FALSE; - if (!gst_element_register (plugin, "alsasrc", GST_RANK_PRIMARY, - GST_TYPE_ALSA_SRC)) - return FALSE; - if (!gst_element_register (plugin, "alsasink", GST_RANK_PRIMARY, - GST_TYPE_ALSA_SINK)) - return FALSE; - - GST_DEBUG_CATEGORY_INIT (alsa_debug, "alsa", 0, "alsa plugins"); - -#if ENABLE_NLS - GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE, - LOCALEDIR); - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); -#endif - - err = snd_lib_error_set_handler (gst_alsa_error_wrapper); - if (err != 0) - GST_WARNING ("failed to set alsa error handler"); - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "alsa", - "ALSA plugin library", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsasink.c --- a/gst_plugins_base/ext/alsa/gstalsasink.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,983 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Wim Taymans - * Copyright (C) 2006 Tim-Philipp Müller - * - * gstalsasink.c: - * - * 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. - */ - -/** - * SECTION:element-alsasink - * @short_description: play audio to an ALSA device - * @see_also: alsasrc, alsamixer - * - * - * - * This element renders raw audio samples using the ALSA api. - * - * Example pipelines - * - * Play an Ogg/Vorbis file. - * - * - * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! alsasink - * - * - * - * Last reviewed on 2006-03-01 (0.10.4) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include -#include -#include -#include -#include - -#include "gstalsa.h" -#include "gstalsasink.h" -#include "gstalsadeviceprobe.h" - -#include - -/* elementfactory information */ -static const GstElementDetails gst_alsasink_details = -GST_ELEMENT_DETAILS ("Audio sink (ALSA)", - "Sink/Audio", - "Output to a sound card via ALSA", - "Wim Taymans "); - -#define DEFAULT_DEVICE "default" -#define DEFAULT_DEVICE_NAME "" -#define SPDIF_PERIOD_SIZE 1536 -#define SPDIF_BUFFER_SIZE 15360 - -enum -{ - PROP_0, - PROP_DEVICE, - PROP_DEVICE_NAME -}; - -static void gst_alsasink_init_interfaces (GType type); - -GST_BOILERPLATE_FULL (GstAlsaSink, gst_alsasink, GstAudioSink, - GST_TYPE_AUDIO_SINK, gst_alsasink_init_interfaces); - -static void gst_alsasink_finalise (GObject * object); -static void gst_alsasink_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_alsasink_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - -static GstCaps *gst_alsasink_getcaps (GstBaseSink * bsink); - -static gboolean gst_alsasink_open (GstAudioSink * asink); -static gboolean gst_alsasink_prepare (GstAudioSink * asink, - GstRingBufferSpec * spec); -static gboolean gst_alsasink_unprepare (GstAudioSink * asink); -static gboolean gst_alsasink_close (GstAudioSink * asink); -static guint gst_alsasink_write (GstAudioSink * asink, gpointer data, - guint length); -static guint gst_alsasink_delay (GstAudioSink * asink); -static void gst_alsasink_reset (GstAudioSink * asink); - -static gint output_ref; /* 0 */ -static snd_output_t *output; /* NULL */ -static GStaticMutex output_mutex = G_STATIC_MUTEX_INIT; - - -#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) -# define ALSA_SINK_FACTORY_ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN" -#else -# define ALSA_SINK_FACTORY_ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN" -#endif - -static GstStaticPadTemplate alsasink_sink_factory = - GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 32, " - "depth = (int) 32, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 24, " - "depth = (int) 24, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 32, " - "depth = (int) 24, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 16, " - "depth = (int) 16, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 8, " - "depth = (int) 8, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ];" - "audio/x-iec958") - ); - -static void -gst_alsasink_finalise (GObject * object) -{ - GstAlsaSink *sink = GST_ALSA_SINK (object); - - g_free (sink->device); - g_mutex_free (sink->alsa_lock); - - g_static_mutex_lock (&output_mutex); - --output_ref; - if (output_ref == 0) { - snd_output_close (output); - output = NULL; - } - g_static_mutex_unlock (&output_mutex); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_alsasink_init_interfaces (GType type) -{ - gst_alsa_type_add_device_property_probe_interface (type); -} - -static void -gst_alsasink_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_alsasink_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&alsasink_sink_factory)); -} -static void -gst_alsasink_class_init (GstAlsaSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - GstBaseAudioSinkClass *gstbaseaudiosink_class; - GstAudioSinkClass *gstaudiosink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass; - gstaudiosink_class = (GstAudioSinkClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_alsasink_finalise); - gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_alsasink_get_property); - gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_alsasink_set_property); - - gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasink_getcaps); - - gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_alsasink_open); - gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasink_prepare); - gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_alsasink_unprepare); - gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_alsasink_close); - gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_alsasink_write); - gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_alsasink_delay); - gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_alsasink_reset); - - g_object_class_install_property (gobject_class, PROP_DEVICE, - g_param_spec_string ("device", "Device", - "ALSA device, as defined in an asound configuration file", - DEFAULT_DEVICE, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_DEVICE_NAME, - g_param_spec_string ("device-name", "Device name", - "Human-readable name of the sound device", DEFAULT_DEVICE_NAME, - G_PARAM_READABLE)); -} - -static void -gst_alsasink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAlsaSink *sink; - - sink = GST_ALSA_SINK (object); - - switch (prop_id) { - case PROP_DEVICE: - g_free (sink->device); - sink->device = g_value_dup_string (value); - /* setting NULL restores the default device */ - if (sink->device == NULL) { - sink->device = g_strdup (DEFAULT_DEVICE); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_alsasink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAlsaSink *sink; - - sink = GST_ALSA_SINK (object); - - switch (prop_id) { - case PROP_DEVICE: - g_value_set_string (value, sink->device); - break; - case PROP_DEVICE_NAME: - g_value_take_string (value, - gst_alsa_find_device_name (GST_OBJECT_CAST (sink), - sink->device, sink->handle, SND_PCM_STREAM_PLAYBACK)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_alsasink_init (GstAlsaSink * alsasink, GstAlsaSinkClass * g_class) -{ - GST_DEBUG_OBJECT (alsasink, "initializing alsasink"); - - alsasink->device = g_strdup (DEFAULT_DEVICE); - alsasink->handle = NULL; - alsasink->cached_caps = NULL; - alsasink->alsa_lock = g_mutex_new (); - - g_static_mutex_lock (&output_mutex); - if (output_ref == 0) { - snd_output_stdio_attach (&output, stdout, 0); - ++output_ref; - } - g_static_mutex_unlock (&output_mutex); -} - -#define CHECK(call, error) \ -G_STMT_START { \ -if ((err = call) < 0) \ - goto error; \ -} G_STMT_END; - -static GstCaps * -gst_alsasink_getcaps (GstBaseSink * bsink) -{ - GstElementClass *element_class; - GstPadTemplate *pad_template; - GstAlsaSink *sink = GST_ALSA_SINK (bsink); - GstCaps *caps; - - if (sink->handle == NULL) { - GST_DEBUG_OBJECT (sink, "device not open, using template caps"); - return NULL; /* base class will get template caps for us */ - } - - if (sink->cached_caps) { - GST_LOG_OBJECT (sink, "Returning cached caps"); - return gst_caps_ref (sink->cached_caps); - } - - element_class = GST_ELEMENT_GET_CLASS (sink); - pad_template = gst_element_class_get_pad_template (element_class, "sink"); - g_return_val_if_fail (pad_template != NULL, NULL); - - caps = gst_alsa_probe_supported_formats (GST_OBJECT (sink), sink->handle, - gst_pad_template_get_caps (pad_template)); - - if (caps) { - sink->cached_caps = gst_caps_ref (caps); - } - - GST_INFO_OBJECT (sink, "returning caps %" GST_PTR_FORMAT, caps); - - return caps; -} - -static int -set_hwparams (GstAlsaSink * alsa) -{ - guint rrate; - gint err, dir; - snd_pcm_hw_params_t *params; - guint period_time, buffer_time; - - snd_pcm_hw_params_malloc (¶ms); - - GST_DEBUG_OBJECT (alsa, "Negotiating to %d channels @ %d Hz (format = %s) " - "SPDIF (%d)", alsa->channels, alsa->rate, - snd_pcm_format_name (alsa->format), alsa->iec958); - - /* start with requested values, if we cannot configure alsa for those values, - * we set these values to -1, which will leave the default alsa values */ - buffer_time = alsa->buffer_time; - period_time = alsa->period_time; - -retry: - /* choose all parameters */ - CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config); - /* set the interleaved read/write format */ - CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access), - wrong_access); - /* set the sample format */ - if (alsa->iec958) { - /* Try to use big endian first else fallback to le and swap bytes */ - if (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format) < 0) { - alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->need_swap = TRUE; - GST_DEBUG_OBJECT (alsa, "falling back to little endian with swapping"); - } else { - alsa->need_swap = FALSE; - } - } - CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format), - no_sample_format); - /* set the count of channels */ - CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels), - no_channels); - /* set the stream rate */ - rrate = alsa->rate; - CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL), - no_rate); - if (rrate != alsa->rate) - goto rate_match; - - /* get and dump some limits */ - { - guint min, max; - - snd_pcm_hw_params_get_buffer_time_min (params, &min, &dir); - snd_pcm_hw_params_get_buffer_time_max (params, &max, &dir); - - GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u", - alsa->buffer_time, min, max); - - snd_pcm_hw_params_get_period_time_min (params, &min, &dir); - snd_pcm_hw_params_get_period_time_max (params, &max, &dir); - - GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u", - alsa->period_time, min, max); - - snd_pcm_hw_params_get_periods_min (params, &min, &dir); - snd_pcm_hw_params_get_periods_max (params, &max, &dir); - - GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max); - } - - /* now try to configure the buffer time and period time, if one - * of those fail, we fall back to the defaults and emit a warning. */ - if (buffer_time != -1 && !alsa->iec958) { - /* set the buffer time */ - if ((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params, - &buffer_time, &dir)) < 0) { - GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set buffer time %i for playback: %s", - buffer_time, snd_strerror (err))); - /* disable buffer_time the next round */ - buffer_time = -1; - goto retry; - } - GST_DEBUG_OBJECT (alsa, "buffer time %u", buffer_time); - } - if (period_time != -1 && !alsa->iec958) { - /* set the period time */ - if ((err = snd_pcm_hw_params_set_period_time_near (alsa->handle, params, - &period_time, &dir)) < 0) { - GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set period time %i for playback: %s", - period_time, snd_strerror (err))); - /* disable period_time the next round */ - period_time = -1; - goto retry; - } - GST_DEBUG_OBJECT (alsa, "period time %u", period_time); - } - - /* Set buffer size and period size manually for SPDIF */ - if (G_UNLIKELY (alsa->iec958)) { - snd_pcm_uframes_t buffer_size = SPDIF_BUFFER_SIZE; - snd_pcm_uframes_t period_size = SPDIF_PERIOD_SIZE; - - CHECK (snd_pcm_hw_params_set_buffer_size_near (alsa->handle, params, - &buffer_size), buffer_size); - CHECK (snd_pcm_hw_params_set_period_size_near (alsa->handle, params, - &period_size, NULL), period_size); - } - - /* write the parameters to device */ - CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params); - - /* now get the configured values */ - CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size), - buffer_size); - CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, &dir), - period_size); - - GST_DEBUG_OBJECT (alsa, "buffer size %lu, period size %lu", alsa->buffer_size, - alsa->period_size); - - snd_pcm_hw_params_free (params); - return 0; - - /* ERRORS */ -no_config: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Broken configuration for playback: no configurations available: %s", - snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -wrong_access: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Access type not available for playback: %s", snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -no_sample_format: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Sample format not available for playback: %s", snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -no_channels: - { - gchar *msg = NULL; - - if ((alsa->channels) == 1) - msg = g_strdup (_("Could not open device for playback in mono mode.")); - if ((alsa->channels) == 2) - msg = g_strdup (_("Could not open device for playback in stereo mode.")); - if ((alsa->channels) > 2) - msg = - g_strdup_printf (_ - ("Could not open device for playback in %d-channel mode."), - alsa->channels); - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (msg), (snd_strerror (err))); - g_free (msg); - snd_pcm_hw_params_free (params); - return err; - } -no_rate: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Rate %iHz not available for playback: %s", - alsa->rate, snd_strerror (err))); - return err; - } -rate_match: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Rate doesn't match (requested %iHz, get %iHz)", alsa->rate, err)); - snd_pcm_hw_params_free (params); - return -EINVAL; - } -buffer_size: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to get buffer size for playback: %s", snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -period_size: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to get period size for playback: %s", snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -set_hw_params: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set hw params for playback: %s", snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -} - -static int -set_swparams (GstAlsaSink * alsa) -{ - int err; - snd_pcm_sw_params_t *params; - - snd_pcm_sw_params_malloc (¶ms); - - /* get the current swparams */ - CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config); - /* start the transfer when the buffer is almost full: */ - /* (buffer_size / avail_min) * avail_min */ - CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params, - (alsa->buffer_size / alsa->period_size) * alsa->period_size), - start_threshold); - - /* allow the transfer when at least period_size samples can be processed */ - CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params, - alsa->period_size), set_avail); - -#if GST_CHECK_ALSA_VERSION(1,0,16) - /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */ -#else - /* align all transfers to 1 sample */ - CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align); -#endif - - /* write the parameters to the playback device */ - CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params); - - snd_pcm_sw_params_free (params); - return 0; - - /* ERRORS */ -no_config: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to determine current swparams for playback: %s", - snd_strerror (err))); - snd_pcm_sw_params_free (params); - return err; - } -start_threshold: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set start threshold mode for playback: %s", - snd_strerror (err))); - snd_pcm_sw_params_free (params); - return err; - } -set_avail: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set avail min for playback: %s", snd_strerror (err))); - snd_pcm_sw_params_free (params); - return err; - } -#if !GST_CHECK_ALSA_VERSION(1,0,16) -set_align: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set transfer align for playback: %s", snd_strerror (err))); - snd_pcm_sw_params_free (params); - return err; - } -#endif -set_sw_params: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set sw params for playback: %s", snd_strerror (err))); - snd_pcm_sw_params_free (params); - return err; - } -} - -static gboolean -alsasink_parse_spec (GstAlsaSink * alsa, GstRingBufferSpec * spec) -{ - /* Initialize our boolean */ - alsa->iec958 = FALSE; - - switch (spec->type) { - case GST_BUFTYPE_LINEAR: - GST_DEBUG_OBJECT (alsa, - "Linear format : depth=%d, width=%d, sign=%d, bigend=%d", spec->depth, - spec->width, spec->sign, spec->bigend); - - alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width, - spec->sign ? 0 : 1, spec->bigend ? 1 : 0); - break; - case GST_BUFTYPE_FLOAT: - switch (spec->format) { - case GST_FLOAT32_LE: - alsa->format = SND_PCM_FORMAT_FLOAT_LE; - break; - case GST_FLOAT32_BE: - alsa->format = SND_PCM_FORMAT_FLOAT_BE; - break; - case GST_FLOAT64_LE: - alsa->format = SND_PCM_FORMAT_FLOAT64_LE; - break; - case GST_FLOAT64_BE: - alsa->format = SND_PCM_FORMAT_FLOAT64_BE; - break; - default: - goto error; - } - break; - case GST_BUFTYPE_A_LAW: - alsa->format = SND_PCM_FORMAT_A_LAW; - break; - case GST_BUFTYPE_MU_LAW: - alsa->format = SND_PCM_FORMAT_MU_LAW; - break; - case GST_BUFTYPE_IEC958: - alsa->format = SND_PCM_FORMAT_S16_BE; - alsa->iec958 = TRUE; - break; - default: - goto error; - - } - alsa->rate = spec->rate; - alsa->channels = spec->channels; - alsa->buffer_time = spec->buffer_time; - alsa->period_time = spec->latency_time; - alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED; - - return TRUE; - - /* ERRORS */ -error: - { - return FALSE; - } -} - -static gboolean -gst_alsasink_open (GstAudioSink * asink) -{ - GstAlsaSink *alsa; - gint err; - - alsa = GST_ALSA_SINK (asink); - - CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_PLAYBACK, - SND_PCM_NONBLOCK), open_error); - GST_LOG_OBJECT (alsa, "Opened device %s", alsa->device); - - return TRUE; - - /* ERRORS */ -open_error: - { - if (err == -EBUSY) { - GST_ELEMENT_ERROR (alsa, RESOURCE, BUSY, - (_("Could not open audio device for playback. " - "Device is being used by another application.")), - ("Device '%s' is busy", alsa->device)); - } else { - GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE, - (_("Could not open audio device for playback.")), - ("Playback open error on device '%s': %s", alsa->device, - snd_strerror (err))); - } - return FALSE; - } -} - -static gboolean -gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) -{ - GstAlsaSink *alsa; - gint err; - - alsa = GST_ALSA_SINK (asink); - - if (spec->format == GST_IEC958) { - snd_pcm_close (alsa->handle); - alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa)); - if (G_UNLIKELY (!alsa->handle)) { - goto no_iec958; - } - } - - if (!alsasink_parse_spec (alsa, spec)) - goto spec_parse; - - CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block); - - CHECK (set_hwparams (alsa), hw_params_failed); - CHECK (set_swparams (alsa), sw_params_failed); - - alsa->bytes_per_sample = spec->bytes_per_sample; - spec->segsize = alsa->period_size * spec->bytes_per_sample; - spec->segtotal = alsa->buffer_size / alsa->period_size; - - { - snd_output_t *out_buf = NULL; - char *msg = NULL; - - snd_output_buffer_open (&out_buf); - snd_pcm_dump_hw_setup (alsa->handle, out_buf); - snd_output_buffer_string (out_buf, &msg); - GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg); - snd_output_close (out_buf); - snd_output_buffer_open (&out_buf); - snd_pcm_dump_sw_setup (alsa->handle, out_buf); - snd_output_buffer_string (out_buf, &msg); - GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg); - snd_output_close (out_buf); - } - - return TRUE; - - /* ERRORS */ -no_iec958: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE, (NULL), - ("Could not open IEC958 (SPDIF) device for playback")); - return FALSE; - } -spec_parse: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Error parsing spec")); - return FALSE; - } -non_block: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Could not set device to blocking: %s", snd_strerror (err))); - return FALSE; - } -hw_params_failed: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Setting of hwparams failed: %s", snd_strerror (err))); - return FALSE; - } -sw_params_failed: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Setting of swparams failed: %s", snd_strerror (err))); - return FALSE; - } -} - -static gboolean -gst_alsasink_unprepare (GstAudioSink * asink) -{ - GstAlsaSink *alsa; - gint err; - - alsa = GST_ALSA_SINK (asink); - - CHECK (snd_pcm_drop (alsa->handle), drop); - - CHECK (snd_pcm_hw_free (alsa->handle), hw_free); - - CHECK (snd_pcm_nonblock (alsa->handle, 1), non_block); - - return TRUE; - - /* ERRORS */ -drop: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Could not drop samples: %s", snd_strerror (err))); - return FALSE; - } -hw_free: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Could not free hw params: %s", snd_strerror (err))); - return FALSE; - } -non_block: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Could not set device to nonblocking: %s", snd_strerror (err))); - return FALSE; - } -} - -static gboolean -gst_alsasink_close (GstAudioSink * asink) -{ - GstAlsaSink *alsa = GST_ALSA_SINK (asink); - gint err; - - if (alsa->handle) { - CHECK (snd_pcm_close (alsa->handle), close_error); - alsa->handle = NULL; - } - gst_caps_replace (&alsa->cached_caps, NULL); - - return TRUE; - - /* ERRORS */ -close_error: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, CLOSE, (NULL), - ("Playback close error: %s", snd_strerror (err))); - return FALSE; - } -} - - -/* - * Underrun and suspend recovery - */ -static gint -xrun_recovery (GstAlsaSink * alsa, snd_pcm_t * handle, gint err) -{ - GST_DEBUG_OBJECT (alsa, "xrun recovery %d", err); - - if (err == -EPIPE) { /* under-run */ - err = snd_pcm_prepare (handle); - if (err < 0) - GST_WARNING_OBJECT (alsa, - "Can't recovery from underrun, prepare failed: %s", - snd_strerror (err)); - return 0; - } else if (err == -ESTRPIPE) { - while ((err = snd_pcm_resume (handle)) == -EAGAIN) - g_usleep (100); /* wait until the suspend flag is released */ - - if (err < 0) { - err = snd_pcm_prepare (handle); - if (err < 0) - GST_WARNING_OBJECT (alsa, - "Can't recovery from suspend, prepare failed: %s", - snd_strerror (err)); - } - return 0; - } - return err; -} - -static guint -gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length) -{ - GstAlsaSink *alsa; - gint err; - gint cptr; - gint16 *ptr = data; - - alsa = GST_ALSA_SINK (asink); - - if (alsa->iec958 && alsa->need_swap) { - guint i; - - GST_DEBUG_OBJECT (asink, "swapping bytes"); - for (i = 0; i < length / 2; i++) { - ptr[i] = GUINT16_SWAP_LE_BE (ptr[i]); - } - } - - GST_LOG_OBJECT (asink, "received audio samples buffer of %u bytes", length); - - cptr = length / alsa->bytes_per_sample; - - GST_ALSA_SINK_LOCK (asink); - while (cptr > 0) { - err = snd_pcm_writei (alsa->handle, ptr, cptr); - - GST_DEBUG_OBJECT (asink, "written %d frames out of %d", err, cptr); - if (err < 0) { - GST_DEBUG_OBJECT (asink, "Write error: %s", snd_strerror (err)); - if (err == -EAGAIN) { - continue; - } else if (xrun_recovery (alsa, alsa->handle, err) < 0) { - goto write_error; - } - continue; - } - - ptr += snd_pcm_frames_to_bytes (alsa->handle, err); - cptr -= err; - } - GST_ALSA_SINK_UNLOCK (asink); - - return length - (cptr * alsa->bytes_per_sample); - -write_error: - { - GST_ALSA_SINK_UNLOCK (asink); - return length; /* skip one period */ - } -} - -static guint -gst_alsasink_delay (GstAudioSink * asink) -{ - GstAlsaSink *alsa; - snd_pcm_sframes_t delay; - int res; - - alsa = GST_ALSA_SINK (asink); - - res = snd_pcm_delay (alsa->handle, &delay); - if (G_UNLIKELY (res < 0)) { - /* on errors, report 0 delay */ - GST_DEBUG_OBJECT (alsa, "snd_pcm_delay returned %d", res); - delay = 0; - } - if (G_UNLIKELY (delay < 0)) { - /* make sure we never return a negative delay */ - GST_WARNING_OBJECT (alsa, "snd_pcm_delay returned negative delay"); - delay = 0; - } - - return delay; -} - -static void -gst_alsasink_reset (GstAudioSink * asink) -{ - GstAlsaSink *alsa; - gint err; - - alsa = GST_ALSA_SINK (asink); - - GST_ALSA_SINK_LOCK (asink); - GST_DEBUG_OBJECT (alsa, "drop"); - CHECK (snd_pcm_drop (alsa->handle), drop_error); - GST_DEBUG_OBJECT (alsa, "prepare"); - CHECK (snd_pcm_prepare (alsa->handle), prepare_error); - GST_DEBUG_OBJECT (alsa, "reset done"); - GST_ALSA_SINK_UNLOCK (asink); - - return; - - /* ERRORS */ -drop_error: - { - GST_ERROR_OBJECT (alsa, "alsa-reset: pcm drop error: %s", - snd_strerror (err)); - GST_ALSA_SINK_UNLOCK (asink); - return; - } -prepare_error: - { - GST_ERROR_OBJECT (alsa, "alsa-reset: pcm prepare error: %s", - snd_strerror (err)); - GST_ALSA_SINK_UNLOCK (asink); - return; - } -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsasink.h --- a/gst_plugins_base/ext/alsa/gstalsasink.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Wim Taymans - * - * gstalsasink.h: - * - * 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. - */ - - -#ifndef __GST_ALSASINK_H__ -#define __GST_ALSASINK_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_ALSA_SINK (gst_alsasink_get_type()) -#define GST_ALSA_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_SINK,GstAlsaSink)) -#define GST_ALSA_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_SINK,GstAlsaSinkClass)) -#define GST_IS_ALSA_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_SINK)) -#define GST_IS_ALSA_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_SINK)) -#define GST_ALSA_SINK_CAST(obj) ((GstAlsaSink *) (obj)) - -typedef struct _GstAlsaSink GstAlsaSink; -typedef struct _GstAlsaSinkClass GstAlsaSinkClass; - -#define GST_ALSA_SINK_GET_LOCK(obj) (GST_ALSA_SINK_CAST (obj)->alsa_lock) -#define GST_ALSA_SINK_LOCK(obj) (g_mutex_lock (GST_ALSA_SINK_GET_LOCK (obj))) -#define GST_ALSA_SINK_UNLOCK(obj) (g_mutex_unlock (GST_ALSA_SINK_GET_LOCK (obj))) - -/** - * GstAlsaSink: - * - * Opaque data structure - */ -struct _GstAlsaSink { - GstAudioSink sink; - - gchar *device; - - snd_pcm_t *handle; - snd_pcm_hw_params_t *hwparams; - snd_pcm_sw_params_t *swparams; - - snd_pcm_access_t access; - snd_pcm_format_t format; - guint rate; - guint channels; - gint bytes_per_sample; - gboolean iec958; - gboolean need_swap; - - guint buffer_time; - guint period_time; - snd_pcm_uframes_t buffer_size; - snd_pcm_uframes_t period_size; - - GstCaps *cached_caps; - - GMutex *alsa_lock; -}; - -struct _GstAlsaSinkClass { - GstAudioSinkClass parent_class; -}; - -GType gst_alsasink_get_type(void); - -G_END_DECLS - -#endif /* __GST_ALSASINK_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsasrc.c --- a/gst_plugins_base/ext/alsa/gstalsasrc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,881 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Wim Taymans - * - * gstalsasrc.c: - * - * 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. - */ - -/** - * SECTION:element-alsasrc - * @short_description: capture audio from an alsa device - * @see_also: alsasink, alsamixer - * - * - * - * This element reads data from an audio card using the ALSA API. - * - * Example pipelines - * - * Record from a sound card using ALSA and encode to Ogg/Vorbis. - * - * - * gst-launch -v alsasrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg - * - * - * - * Last reviewed on 2006-03-01 (0.10.4) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include -#include -#include -#include -#include - -#include "gstalsasrc.h" -#include "gstalsadeviceprobe.h" - -#include - -/* elementfactory information */ -static const GstElementDetails gst_alsasrc_details = -GST_ELEMENT_DETAILS ("Audio source (ALSA)", - "Source/Audio", - "Read from a sound card via ALSA", - "Wim Taymans "); - -#define DEFAULT_PROP_DEVICE "default" -#define DEFAULT_PROP_DEVICE_NAME "" - -enum -{ - PROP_0, - PROP_DEVICE, - PROP_DEVICE_NAME, -}; - -static void gst_alsasrc_init_interfaces (GType type); - -GST_BOILERPLATE_FULL (GstAlsaSrc, gst_alsasrc, GstAudioSrc, - GST_TYPE_AUDIO_SRC, gst_alsasrc_init_interfaces); - -GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaSrc, gst_alsasrc_mixer); - -static void gst_alsasrc_finalize (GObject * object); -static void gst_alsasrc_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_alsasrc_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - -static GstCaps *gst_alsasrc_getcaps (GstBaseSrc * bsrc); - -static gboolean gst_alsasrc_open (GstAudioSrc * asrc); -static gboolean gst_alsasrc_prepare (GstAudioSrc * asrc, - GstRingBufferSpec * spec); -static gboolean gst_alsasrc_unprepare (GstAudioSrc * asrc); -static gboolean gst_alsasrc_close (GstAudioSrc * asrc); -static guint gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length); -static guint gst_alsasrc_delay (GstAudioSrc * asrc); -static void gst_alsasrc_reset (GstAudioSrc * asrc); - -/* AlsaSrc signals and args */ -enum -{ - LAST_SIGNAL -}; - -#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) -# define ALSA_SRC_FACTORY_ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN" -#else -# define ALSA_SRC_FACTORY_ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN" -#endif - -static GstStaticPadTemplate alsasrc_src_factory = - GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 32, " - "depth = (int) 32, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 32, " - "depth = (int) 24, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 24, " - "depth = (int) 24, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 16, " - "depth = (int) 16, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; " - "audio/x-raw-int, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) 8, " - "depth = (int) 8, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]") - ); - -static void -gst_alsasrc_finalize (GObject * object) -{ - GstAlsaSrc *src = GST_ALSA_SRC (object); - - g_free (src->device); - g_mutex_free (src->alsa_lock); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -gst_alsasrc_interface_supported (GstAlsaSrc * this, GType interface_type) -{ - /* only support this one interface (wrapped by GstImplementsInterface) */ - g_assert (interface_type == GST_TYPE_MIXER); - - return gst_alsasrc_mixer_supported (this, interface_type); -} - -static void -gst_implements_interface_init (GstImplementsInterfaceClass * klass) -{ - klass->supported = (gpointer) gst_alsasrc_interface_supported; -} - -static void -gst_alsasrc_init_interfaces (GType type) -{ - static const GInterfaceInfo implements_iface_info = { - (GInterfaceInitFunc) gst_implements_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo mixer_iface_info = { - (GInterfaceInitFunc) gst_alsasrc_mixer_interface_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, - &implements_iface_info); - g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info); - - gst_alsa_type_add_device_property_probe_interface (type); -} - -static void -gst_alsasrc_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_alsasrc_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&alsasrc_src_factory)); -} - -static void -gst_alsasrc_class_init (GstAlsaSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSrcClass *gstbasesrc_class; - GstBaseAudioSrcClass *gstbaseaudiosrc_class; - GstAudioSrcClass *gstaudiosrc_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesrc_class = (GstBaseSrcClass *) klass; - gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass; - gstaudiosrc_class = (GstAudioSrcClass *) klass; - - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_alsasrc_finalize); - gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_alsasrc_get_property); - gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_alsasrc_set_property); - - gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasrc_getcaps); - - gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_alsasrc_open); - gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasrc_prepare); - gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_alsasrc_unprepare); - gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_alsasrc_close); - gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_alsasrc_read); - gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_alsasrc_delay); - gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_alsasrc_reset); - - g_object_class_install_property (gobject_class, PROP_DEVICE, - g_param_spec_string ("device", "Device", - "ALSA device, as defined in an asound configuration file", - DEFAULT_PROP_DEVICE, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_DEVICE_NAME, - g_param_spec_string ("device-name", "Device name", - "Human-readable name of the sound device", - DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE)); -} - -static void -gst_alsasrc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAlsaSrc *src; - - src = GST_ALSA_SRC (object); - - switch (prop_id) { - case PROP_DEVICE: - g_free (src->device); - src->device = g_value_dup_string (value); - if (src->device == NULL) { - src->device = g_strdup (DEFAULT_PROP_DEVICE); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_alsasrc_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAlsaSrc *src; - - src = GST_ALSA_SRC (object); - - switch (prop_id) { - case PROP_DEVICE: - g_value_set_string (value, src->device); - break; - case PROP_DEVICE_NAME: - g_value_take_string (value, - gst_alsa_find_device_name (GST_OBJECT_CAST (src), - src->device, src->handle, SND_PCM_STREAM_CAPTURE)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_alsasrc_init (GstAlsaSrc * alsasrc, GstAlsaSrcClass * g_class) -{ - GST_DEBUG_OBJECT (alsasrc, "initializing"); - - alsasrc->device = g_strdup (DEFAULT_PROP_DEVICE); - alsasrc->cached_caps = NULL; - - alsasrc->alsa_lock = g_mutex_new (); -} - -#define CHECK(call, error) \ -G_STMT_START { \ -if ((err = call) < 0) \ - goto error; \ -} G_STMT_END; - - -static GstCaps * -gst_alsasrc_getcaps (GstBaseSrc * bsrc) -{ - GstElementClass *element_class; - GstPadTemplate *pad_template; - GstAlsaSrc *src; - GstCaps *caps; - - src = GST_ALSA_SRC (bsrc); - - if (src->handle == NULL) { - GST_DEBUG_OBJECT (src, "device not open, using template caps"); - return NULL; /* base class will get template caps for us */ - } - - if (src->cached_caps) { - GST_LOG_OBJECT (src, "Returning cached caps"); - return gst_caps_ref (src->cached_caps); - } - - element_class = GST_ELEMENT_GET_CLASS (src); - pad_template = gst_element_class_get_pad_template (element_class, "src"); - g_return_val_if_fail (pad_template != NULL, NULL); - - caps = gst_alsa_probe_supported_formats (GST_OBJECT (src), src->handle, - gst_pad_template_get_caps (pad_template)); - - if (caps) { - src->cached_caps = gst_caps_ref (caps); - } - - GST_INFO_OBJECT (src, "returning caps %" GST_PTR_FORMAT, caps); - - return caps; -} - -static int -set_hwparams (GstAlsaSrc * alsa) -{ - guint rrate; - gint err, dir; - snd_pcm_hw_params_t *params; - - snd_pcm_hw_params_malloc (¶ms); - - /* choose all parameters */ - CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config); - /* set the interleaved read/write format */ - CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access), - wrong_access); - /* set the sample format */ - CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format), - no_sample_format); - /* set the count of channels */ - CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels), - no_channels); - /* set the stream rate */ - rrate = alsa->rate; - CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL), - no_rate); - if (rrate != alsa->rate) - goto rate_match; - - if (alsa->buffer_time != -1) { - /* set the buffer time */ - CHECK (snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params, - &alsa->buffer_time, &dir), buffer_time); - } - if (alsa->period_time != -1) { - /* set the period time */ - CHECK (snd_pcm_hw_params_set_period_time_near (alsa->handle, params, - &alsa->period_time, &dir), period_time); - } - - /* write the parameters to device */ - CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params); - - CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size), - buffer_size); - - CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, &dir), - period_size); - - snd_pcm_hw_params_free (params); - return 0; - - /* ERRORS */ -no_config: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Broken configuration for recording: no configurations available: %s", - snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -wrong_access: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Access type not available for recording: %s", snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -no_sample_format: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Sample format not available for recording: %s", snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -no_channels: - { - gchar *msg = NULL; - - if ((alsa->channels) == 1) - msg = g_strdup (_("Could not open device for recording in mono mode.")); - if ((alsa->channels) == 2) - msg = g_strdup (_("Could not open device for recording in stereo mode.")); - if ((alsa->channels) > 2) - msg = - g_strdup_printf (_ - ("Could not open device for recording in %d-channel mode"), - alsa->channels); - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (msg), (snd_strerror (err))); - g_free (msg); - snd_pcm_hw_params_free (params); - return err; - } -no_rate: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Rate %iHz not available for recording: %s", - alsa->rate, snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -rate_match: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Rate doesn't match (requested %iHz, get %iHz)", alsa->rate, err)); - snd_pcm_hw_params_free (params); - return -EINVAL; - } -buffer_time: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set buffer time %i for recording: %s", - alsa->buffer_time, snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -buffer_size: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to get buffer size for recording: %s", snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -period_time: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set period time %i for recording: %s", alsa->period_time, - snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -period_size: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to get period size for recording: %s", snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -set_hw_params: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set hw params for recording: %s", snd_strerror (err))); - snd_pcm_hw_params_free (params); - return err; - } -} - -static int -set_swparams (GstAlsaSrc * alsa) -{ - int err; - snd_pcm_sw_params_t *params; - - snd_pcm_sw_params_malloc (¶ms); - - /* get the current swparams */ - CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config); - /* allow the transfer when at least period_size samples can be processed */ - CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params, - alsa->period_size), set_avail); - /* start the transfer on first read */ - CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params, - 0), start_threshold); - -#if GST_CHECK_ALSA_VERSION(1,0,16) - /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */ -#else - /* align all transfers to 1 sample */ - CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align); -#endif - - /* write the parameters to the recording device */ - CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params); - - snd_pcm_sw_params_free (params); - return 0; - - /* ERRORS */ -no_config: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to determine current swparams for playback: %s", - snd_strerror (err))); - snd_pcm_sw_params_free (params); - return err; - } -start_threshold: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set start threshold mode for playback: %s", - snd_strerror (err))); - snd_pcm_sw_params_free (params); - return err; - } -set_avail: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set avail min for playback: %s", snd_strerror (err))); - snd_pcm_sw_params_free (params); - return err; - } -#if !GST_CHECK_ALSA_VERSION(1,0,16) -set_align: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set transfer align for playback: %s", snd_strerror (err))); - snd_pcm_sw_params_free (params); - return err; - } -#endif -set_sw_params: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Unable to set sw params for playback: %s", snd_strerror (err))); - snd_pcm_sw_params_free (params); - return err; - } -} - -static gboolean -alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec) -{ - switch (spec->type) { - case GST_BUFTYPE_LINEAR: - alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width, - spec->sign ? 0 : 1, spec->bigend ? 1 : 0); - break; - case GST_BUFTYPE_FLOAT: - switch (spec->format) { - case GST_FLOAT32_LE: - alsa->format = SND_PCM_FORMAT_FLOAT_LE; - break; - case GST_FLOAT32_BE: - alsa->format = SND_PCM_FORMAT_FLOAT_BE; - break; - case GST_FLOAT64_LE: - alsa->format = SND_PCM_FORMAT_FLOAT64_LE; - break; - case GST_FLOAT64_BE: - alsa->format = SND_PCM_FORMAT_FLOAT64_BE; - break; - default: - goto error; - } - break; - case GST_BUFTYPE_A_LAW: - alsa->format = SND_PCM_FORMAT_A_LAW; - break; - case GST_BUFTYPE_MU_LAW: - alsa->format = SND_PCM_FORMAT_MU_LAW; - break; - default: - goto error; - - } - alsa->rate = spec->rate; - alsa->channels = spec->channels; - alsa->buffer_time = spec->buffer_time; - alsa->period_time = spec->latency_time; - alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED; - - return TRUE; - - /* ERRORS */ -error: - { - return FALSE; - } -} - -static gboolean -gst_alsasrc_open (GstAudioSrc * asrc) -{ - GstAlsaSrc *alsa; - gint err; - - alsa = GST_ALSA_SRC (asrc); - - CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_CAPTURE, - SND_PCM_NONBLOCK), open_error); - - if (!alsa->mixer) - alsa->mixer = gst_alsa_mixer_new (alsa->device, GST_ALSA_MIXER_CAPTURE); - - return TRUE; - - /* ERRORS */ -open_error: - { - if (err == -EBUSY) { - GST_ELEMENT_ERROR (alsa, RESOURCE, BUSY, - (_("Could not open audio device for recording. " - "Device is being used by another application.")), - ("Device '%s' is busy", alsa->device)); - } else { - GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ, - (_("Could not open audio device for recording.")), - ("Recording open error on device '%s': %s", alsa->device, - snd_strerror (err))); - } - return FALSE; - } -} - -static gboolean -gst_alsasrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) -{ - GstAlsaSrc *alsa; - gint err; - - alsa = GST_ALSA_SRC (asrc); - - if (!alsasrc_parse_spec (alsa, spec)) - goto spec_parse; - - CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block); - - CHECK (set_hwparams (alsa), hw_params_failed); - CHECK (set_swparams (alsa), sw_params_failed); - CHECK (snd_pcm_prepare (alsa->handle), prepare_failed); - - alsa->bytes_per_sample = spec->bytes_per_sample; - spec->segsize = alsa->period_size * spec->bytes_per_sample; - spec->segtotal = alsa->buffer_size / alsa->period_size; - spec->silence_sample[0] = 0; - spec->silence_sample[1] = 0; - spec->silence_sample[2] = 0; - spec->silence_sample[3] = 0; - - return TRUE; - - /* ERRORS */ -spec_parse: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Error parsing spec")); - return FALSE; - } -non_block: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Could not set device to blocking: %s", snd_strerror (err))); - return FALSE; - } -hw_params_failed: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Setting of hwparams failed: %s", snd_strerror (err))); - return FALSE; - } -sw_params_failed: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Setting of swparams failed: %s", snd_strerror (err))); - return FALSE; - } -prepare_failed: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Prepare failed: %s", snd_strerror (err))); - return FALSE; - } -} - -static gboolean -gst_alsasrc_unprepare (GstAudioSrc * asrc) -{ - GstAlsaSrc *alsa; - gint err; - - alsa = GST_ALSA_SRC (asrc); - - CHECK (snd_pcm_drop (alsa->handle), drop); - - CHECK (snd_pcm_hw_free (alsa->handle), hw_free); - - CHECK (snd_pcm_nonblock (alsa->handle, 1), non_block); - - return TRUE; - - /* ERRORS */ -drop: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Could not drop samples: %s", snd_strerror (err))); - return FALSE; - } -hw_free: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Could not free hw params: %s", snd_strerror (err))); - return FALSE; - } -non_block: - { - GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), - ("Could not set device to nonblocking: %s", snd_strerror (err))); - return FALSE; - } -} - -static gboolean -gst_alsasrc_close (GstAudioSrc * asrc) -{ - GstAlsaSrc *alsa = GST_ALSA_SRC (asrc); - - snd_pcm_close (alsa->handle); - - if (alsa->mixer) { - gst_alsa_mixer_free (alsa->mixer); - alsa->mixer = NULL; - } - - gst_caps_replace (&alsa->cached_caps, NULL); - - return TRUE; -} - -/* - * Underrun and suspend recovery - */ -static gint -xrun_recovery (GstAlsaSrc * alsa, snd_pcm_t * handle, gint err) -{ - GST_DEBUG_OBJECT (alsa, "xrun recovery %d", err); - - if (err == -EPIPE) { /* under-run */ - err = snd_pcm_prepare (handle); - if (err < 0) - GST_WARNING_OBJECT (alsa, - "Can't recovery from underrun, prepare failed: %s", - snd_strerror (err)); - return 0; - } else if (err == -ESTRPIPE) { - while ((err = snd_pcm_resume (handle)) == -EAGAIN) - g_usleep (100); /* wait until the suspend flag is released */ - - if (err < 0) { - err = snd_pcm_prepare (handle); - if (err < 0) - GST_WARNING_OBJECT (alsa, - "Can't recovery from suspend, prepare failed: %s", - snd_strerror (err)); - } - return 0; - } - return err; -} - -static guint -gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length) -{ - GstAlsaSrc *alsa; - gint err; - gint cptr; - gint16 *ptr; - - alsa = GST_ALSA_SRC (asrc); - - cptr = length / alsa->bytes_per_sample; - ptr = data; - - GST_ALSA_SRC_LOCK (asrc); - while (cptr > 0) { - if ((err = snd_pcm_readi (alsa->handle, ptr, cptr)) < 0) { - if (err == -EAGAIN) { - GST_DEBUG_OBJECT (asrc, "Read error: %s", snd_strerror (err)); - continue; - } else if (xrun_recovery (alsa, alsa->handle, err) < 0) { - goto read_error; - } - continue; - } - - ptr += err * alsa->channels; - cptr -= err; - } - GST_ALSA_SRC_UNLOCK (asrc); - - return length - cptr; - -read_error: - { - GST_ALSA_SRC_UNLOCK (asrc); - return length; /* skip one period */ - } -} - -static guint -gst_alsasrc_delay (GstAudioSrc * asrc) -{ - GstAlsaSrc *alsa; - snd_pcm_sframes_t delay; - int res; - - alsa = GST_ALSA_SRC (asrc); - - res = snd_pcm_delay (alsa->handle, &delay); - if (G_UNLIKELY (res < 0)) { - GST_DEBUG_OBJECT (alsa, "snd_pcm_delay returned %d", res); - delay = 0; - } - - return CLAMP (delay, 0, alsa->buffer_size); -} - -static void -gst_alsasrc_reset (GstAudioSrc * asrc) -{ - GstAlsaSrc *alsa; - gint err; - - alsa = GST_ALSA_SRC (asrc); - - GST_ALSA_SRC_LOCK (asrc); - GST_DEBUG_OBJECT (alsa, "drop"); - CHECK (snd_pcm_drop (alsa->handle), drop_error); - GST_DEBUG_OBJECT (alsa, "prepare"); - CHECK (snd_pcm_prepare (alsa->handle), prepare_error); - GST_DEBUG_OBJECT (alsa, "reset done"); - GST_ALSA_SRC_UNLOCK (asrc); - - return; - - /* ERRORS */ -drop_error: - { - GST_ERROR_OBJECT (alsa, "alsa-reset: pcm drop error: %s", - snd_strerror (err)); - GST_ALSA_SRC_UNLOCK (asrc); - return; - } -prepare_error: - { - GST_ERROR_OBJECT (alsa, "alsa-reset: pcm prepare error: %s", - snd_strerror (err)); - GST_ALSA_SRC_UNLOCK (asrc); - return; - } -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/alsa/gstalsasrc.h --- a/gst_plugins_base/ext/alsa/gstalsasrc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Wim Taymans - * - * gstalsasrc.h: - * - * 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. - */ - - -#ifndef __GST_ALSASRC_H__ -#define __GST_ALSASRC_H__ - -#include -#include "gstalsa.h" -#include "gstalsamixer.h" - -G_BEGIN_DECLS - -#define GST_TYPE_ALSA_SRC (gst_alsasrc_get_type()) -#define GST_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_SRC,GstAlsaSrc)) -#define GST_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_SRC,GstAlsaSrcClass)) -#define GST_IS_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_SRC)) -#define GST_IS_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_SRC)) -#define GST_ALSA_SRC_CAST(obj) ((GstAlsaSrc *)(obj)) - -#define GST_ALSA_SRC_GET_LOCK(obj) (GST_ALSA_SRC_CAST (obj)->alsa_lock) -#define GST_ALSA_SRC_LOCK(obj) (g_mutex_lock (GST_ALSA_SRC_GET_LOCK (obj))) -#define GST_ALSA_SRC_UNLOCK(obj) (g_mutex_unlock (GST_ALSA_SRC_GET_LOCK (obj))) - -typedef struct _GstAlsaSrc GstAlsaSrc; -typedef struct _GstAlsaSrcClass GstAlsaSrcClass; - -/** - * GstAlsaSrc: - * - * Opaque data structure - */ -struct _GstAlsaSrc { - GstAudioSrc src; - - gchar *device; - - snd_pcm_t *handle; - snd_pcm_hw_params_t *hwparams; - snd_pcm_sw_params_t *swparams; - - GstCaps *cached_caps; - - snd_pcm_access_t access; - snd_pcm_format_t format; - guint rate; - guint channels; - gint bytes_per_sample; - - guint buffer_time; - guint period_time; - snd_pcm_uframes_t buffer_size; - snd_pcm_uframes_t period_size; - - GstAlsaMixer *mixer; - - GMutex *alsa_lock; -}; - -struct _GstAlsaSrcClass { - GstAudioSrcClass parent_class; -}; - -GType gst_alsasrc_get_type(void); - -G_END_DECLS - -#endif /* __GST_ALSASRC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/cdparanoia/gstcdparanoiasrc.c --- a/gst_plugins_base/ext/cdparanoia/gstcdparanoiasrc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,490 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * <2005> Wim Taymans - * <2005> Tim-Philipp Müller - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include "gstcdparanoiasrc.h" -#include "gst/gst-i18n-plugin.h" - -enum -{ - TRANSPORT_ERROR, - UNCORRECTED_ERROR, - NUM_SIGNALS -}; - -enum -{ - PROP_0, - PROP_READ_SPEED, - PROP_PARANOIA_MODE, - PROP_SEARCH_OVERLAP, - PROP_GENERIC_DEVICE -}; - -#define DEFAULT_READ_SPEED -1 -#define DEFAULT_SEARCH_OVERLAP -1 -#define DEFAULT_PARANOIA_MODE PARANOIA_MODE_FRAGMENT -#define DEFAULT_GENERIC_DEVICE NULL - -GST_DEBUG_CATEGORY_STATIC (gst_cd_paranoia_src_debug); -#define GST_CAT_DEFAULT gst_cd_paranoia_src_debug - -GST_BOILERPLATE (GstCdParanoiaSrc, gst_cd_paranoia_src, GstCddaBaseSrc, - GST_TYPE_CDDA_BASE_SRC); - -static void gst_cd_paranoia_src_finalize (GObject * obj); -static void gst_cd_paranoia_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_cd_paranoia_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static GstBuffer *gst_cd_paranoia_src_read_sector (GstCddaBaseSrc * src, - gint sector); -static gboolean gst_cd_paranoia_src_open (GstCddaBaseSrc * src, - const gchar * device); -static void gst_cd_paranoia_src_close (GstCddaBaseSrc * src); - -static const GstElementDetails cdparanoia_details = -GST_ELEMENT_DETAILS ("CD Audio (cdda) Source, Paranoia IV", - "Source/File", - "Read audio from CD in paranoid mode", - "Erik Walthinsen , " "Wim Taymans "); - -/* We use these to serialize calls to paranoia_read() among several - * cdparanoiasrc instances. We do this because it's the only reasonably - * easy way to find out the calling object from within the paranoia - * callback, and we need the object instance in there to emit our signals */ -static GstCdParanoiaSrc *cur_cb_source; -static GStaticMutex cur_cb_mutex = G_STATIC_MUTEX_INIT; - -static gint cdpsrc_signals[NUM_SIGNALS]; /* all 0 */ - -#define GST_TYPE_CD_PARANOIA_MODE (gst_cd_paranoia_mode_get_type()) -static GType -gst_cd_paranoia_mode_get_type (void) -{ - static const GFlagsValue paranoia_modes[] = { - {PARANOIA_MODE_DISABLE, "PARANOIA_MODE_DISABLE", "disable"}, - {PARANOIA_MODE_FRAGMENT, "PARANOIA_MODE_FRAGMENT", "fragment"}, - {PARANOIA_MODE_OVERLAP, "PARANOIA_MODE_OVERLAP", "overlap"}, - {PARANOIA_MODE_SCRATCH, "PARANOIA_MODE_SCRATCH", "scratch"}, - {PARANOIA_MODE_REPAIR, "PARANOIA_MODE_REPAIR", "repair"}, - {PARANOIA_MODE_FULL, "PARANOIA_MODE_FULL", "full"}, - {0, NULL, NULL}, - }; - - static GType type; /* 0 */ - - if (!type) { - type = g_flags_register_static ("GstCdParanoiaMode", paranoia_modes); - } - - return type; -} - -static void -gst_cd_paranoia_src_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &cdparanoia_details); -} - -static void -gst_cd_paranoia_src_init (GstCdParanoiaSrc * src, GstCdParanoiaSrcClass * klass) -{ - src->d = NULL; - src->p = NULL; - src->next_sector = -1; - - src->search_overlap = DEFAULT_SEARCH_OVERLAP; - src->paranoia_mode = DEFAULT_PARANOIA_MODE; - src->read_speed = DEFAULT_READ_SPEED; - src->generic_device = g_strdup (DEFAULT_GENERIC_DEVICE); -} - -static void -gst_cd_paranoia_src_class_init (GstCdParanoiaSrcClass * klass) -{ - GstCddaBaseSrcClass *cddabasesrc_class = GST_CDDA_BASE_SRC_CLASS (klass); - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->set_property = gst_cd_paranoia_src_set_property; - gobject_class->get_property = gst_cd_paranoia_src_get_property; - gobject_class->finalize = gst_cd_paranoia_src_finalize; - - cddabasesrc_class->open = gst_cd_paranoia_src_open; - cddabasesrc_class->close = gst_cd_paranoia_src_close; - cddabasesrc_class->read_sector = gst_cd_paranoia_src_read_sector; - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GENERIC_DEVICE, - g_param_spec_string ("generic-device", "Generic device", - "Use specified generic scsi device", DEFAULT_GENERIC_DEVICE, - G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_READ_SPEED, - g_param_spec_int ("read-speed", "Read speed", - "Read from device at specified speed", -1, G_MAXINT, - DEFAULT_READ_SPEED, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PARANOIA_MODE, - g_param_spec_flags ("paranoia-mode", "Paranoia mode", - "Type of checking to perform", GST_TYPE_CD_PARANOIA_MODE, - DEFAULT_PARANOIA_MODE, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEARCH_OVERLAP, - g_param_spec_int ("search-overlap", "Search overlap", - "Force minimum overlap search during verification to n sectors", -1, - 75, DEFAULT_SEARCH_OVERLAP, G_PARAM_READWRITE)); - - /* FIXME: we don't really want signals for this, but messages on the bus, - * but then we can't check any longer whether anyone is interested in them */ - cdpsrc_signals[TRANSPORT_ERROR] = - g_signal_new ("transport-error", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstCdParanoiaSrcClass, transport_error), - NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - cdpsrc_signals[UNCORRECTED_ERROR] = - g_signal_new ("uncorrected-error", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstCdParanoiaSrcClass, uncorrected_error), - NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); -} - -static gboolean -gst_cd_paranoia_src_open (GstCddaBaseSrc * cddabasesrc, const gchar * device) -{ - GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (cddabasesrc); - gint i; - - GST_DEBUG_OBJECT (src, "trying to open device %s (generic-device=%s) ...", - device, GST_STR_NULL (src->generic_device)); - - /* find the device */ - if (src->generic_device != NULL) { - src->d = cdda_identify_scsi (src->generic_device, device, FALSE, NULL); - } else { - if (device != NULL) { - src->d = cdda_identify (device, FALSE, NULL); - } else { - src->d = cdda_identify ("/dev/cdrom", FALSE, NULL); - } - } - - /* fail if the device couldn't be found */ - if (src->d == NULL) - goto no_device; - - /* set verbosity mode */ - cdda_verbose_set (src->d, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT); - - /* open the disc */ - if (cdda_open (src->d)) - goto open_failed; - - if (src->read_speed != -1) { - cdda_speed_set (src->d, src->read_speed); - } - - for (i = 1; i < src->d->tracks + 1; i++) { - GstCddaBaseSrcTrack track = { 0, }; - - track.num = i; - track.is_audio = IS_AUDIO (src->d, i - 1); - track.start = cdda_track_firstsector (src->d, i); - track.end = cdda_track_lastsector (src->d, i); - track.tags = NULL; - - gst_cdda_base_src_add_track (GST_CDDA_BASE_SRC (src), &track); - } - - /* create the paranoia struct and set it up */ - src->p = paranoia_init (src->d); - if (src->p == NULL) - goto init_failed; - - paranoia_modeset (src->p, src->paranoia_mode); - - if (src->search_overlap != -1) - paranoia_overlapset (src->p, src->search_overlap); - - src->next_sector = -1; - - return TRUE; - - /* ERRORS */ -no_device: - { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, - (_("Could not open CD device for reading.")), ("cdda_identify failed")); - return FALSE; - } -open_failed: - { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, - (_("Could not open CD device for reading.")), ("cdda_open failed")); - cdda_close (src->d); - src->d = NULL; - return FALSE; - } -init_failed: - { - GST_ELEMENT_ERROR (src, LIBRARY, INIT, - ("failed to initialize paranoia"), ("failed to initialize paranoia")); - return FALSE; - } -} - -static void -gst_cd_paranoia_src_close (GstCddaBaseSrc * cddabasesrc) -{ - GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (cddabasesrc); - - if (src->p) { - paranoia_free (src->p); - src->p = NULL; - } - - if (src->d) { - cdda_close (src->d); - src->d = NULL; - } - - src->next_sector = -1; -} - -static void -gst_cd_paranoia_dummy_callback (long inpos, int function) -{ - /* Used by instanced where no one is interested what's happening here */ -} - -static void -gst_cd_paranoia_paranoia_callback (long inpos, int function) -{ - GstCdParanoiaSrc *src = cur_cb_source; - gint sector = (gint) (inpos / CD_FRAMEWORDS); - - switch (function) { - case PARANOIA_CB_SKIP: - GST_INFO_OBJECT (src, "Skip at sector %d", sector); - g_signal_emit (src, cdpsrc_signals[UNCORRECTED_ERROR], 0, sector); - break; - case PARANOIA_CB_READERR: - GST_INFO_OBJECT (src, "Transport error at sector %d", sector); - g_signal_emit (src, cdpsrc_signals[TRANSPORT_ERROR], 0, sector); - break; - default: - break; - } -} - -static gboolean -gst_cd_paranoia_src_signal_is_being_watched (GstCdParanoiaSrc * src, gint sig) -{ - return g_signal_has_handler_pending (src, cdpsrc_signals[sig], 0, FALSE); -} - -static GstBuffer * -gst_cd_paranoia_src_read_sector (GstCddaBaseSrc * cddabasesrc, gint sector) -{ - GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (cddabasesrc); - GstBuffer *buf; - gboolean do_serialize; - gint16 *cdda_buf; - -#if 0 - /* Do we really need to output this? (tpm) */ - /* Due to possible autocorrections of start sectors of audio tracks on - * multisession cds, we can maybe not compute the correct discid. - * So issue a warning. - * See cdparanoia/interface/common-interface.c:FixupTOC */ - if (src->d && src->d->cd_extra) { - g_message - ("DiscID on multisession discs might be broken. Use at own risk."); - } -#endif - - if (src->next_sector == -1 || src->next_sector != sector) { - if (paranoia_seek (src->p, sector, SEEK_SET) == -1) - goto seek_failed; - - GST_DEBUG_OBJECT (src, "successfully seeked to sector %d", sector); - src->next_sector = sector; - } - - do_serialize = - gst_cd_paranoia_src_signal_is_being_watched (src, TRANSPORT_ERROR) || - gst_cd_paranoia_src_signal_is_being_watched (src, UNCORRECTED_ERROR); - - if (do_serialize) { - GST_LOG_OBJECT (src, "Signal handlers connected, serialising access"); - g_static_mutex_lock (&cur_cb_mutex); - GST_LOG_OBJECT (src, "Got lock"); - cur_cb_source = src; - - cdda_buf = paranoia_read (src->p, gst_cd_paranoia_paranoia_callback); - - cur_cb_source = NULL; - GST_LOG_OBJECT (src, "Releasing lock"); - g_static_mutex_unlock (&cur_cb_mutex); - } else { - cdda_buf = paranoia_read (src->p, gst_cd_paranoia_dummy_callback); - } - - if (cdda_buf == NULL) - goto read_failed; - - buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW); - memcpy (GST_BUFFER_DATA (buf), cdda_buf, CD_FRAMESIZE_RAW); - - /* cdda base class will take care of timestamping etc. */ - ++src->next_sector; - - return buf; - - /* ERRORS */ -seek_failed: - { - GST_WARNING_OBJECT (src, "seek to sector %d failed!", sector); - GST_ELEMENT_ERROR (src, RESOURCE, SEEK, - (_("Could not seek CD.")), - ("paranoia_seek to %d failed: %s", sector, g_strerror (errno))); - return NULL; - } -read_failed: - { - GST_WARNING_OBJECT (src, "read at sector %d failed!", sector); - GST_ELEMENT_ERROR (src, RESOURCE, READ, - (_("Could not read CD.")), - ("paranoia_read at %d failed: %s", sector, g_strerror (errno))); - return NULL; - } -} - -static void -gst_cd_paranoia_src_finalize (GObject * obj) -{ - GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (obj); - - g_free (src->generic_device); - - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static void -gst_cd_paranoia_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (object); - - GST_OBJECT_LOCK (src); - - switch (prop_id) { - case PROP_GENERIC_DEVICE:{ - g_free (src->generic_device); - src->generic_device = g_value_dup_string (value); - if (src->generic_device && src->generic_device[0] == '\0') { - g_free (src->generic_device); - src->generic_device = NULL; - } - break; - } - case PROP_READ_SPEED:{ - src->read_speed = g_value_get_int (value); - if (src->read_speed == 0) - src->read_speed = -1; - break; - } - case PROP_PARANOIA_MODE:{ - src->paranoia_mode = g_value_get_flags (value) & PARANOIA_MODE_FULL; - break; - } - case PROP_SEARCH_OVERLAP:{ - src->search_overlap = g_value_get_int (value); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - GST_OBJECT_UNLOCK (src); -} - -static void -gst_cd_paranoia_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (object); - - GST_OBJECT_LOCK (src); - - switch (prop_id) { - case PROP_READ_SPEED: - g_value_set_int (value, src->read_speed); - break; - case PROP_PARANOIA_MODE: - g_value_set_flags (value, src->paranoia_mode); - break; - case PROP_GENERIC_DEVICE: - g_value_set_string (value, src->generic_device); - break; - case PROP_SEARCH_OVERLAP: - g_value_set_int (value, src->search_overlap); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - GST_OBJECT_UNLOCK (src); -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (gst_cd_paranoia_src_debug, "cdparanoiasrc", 0, - "CD Paranoia Source"); - - if (!gst_element_register (plugin, "cdparanoiasrc", GST_RANK_SECONDARY, - GST_TYPE_CD_PARANOIA_SRC)) - return FALSE; - -#ifdef ENABLE_NLS - GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE, - LOCALEDIR); - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); -#endif - - - return TRUE; -} - - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "cdparanoia", - "Read audio from CD in paranoid mode", - plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/cdparanoia/gstcdparanoiasrc.h --- a/gst_plugins_base/ext/cdparanoia/gstcdparanoiasrc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* GStreamer - * Copyright (C) 1999 Erik Walthinsen - * - * 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. - */ - -#ifndef __GST_CD_PARANOIA_SRC_H__ -#define __GST_CD_PARANOIA_SRC_H__ - -#include "gst/cdda/gstcddabasesrc.h" - -G_BEGIN_DECLS - -#define size16 gint16 -#define size32 gint32 - -#ifdef CDPARANOIA_HEADERS_IN_DIR - #include - #include -#else - #include - #include -#endif - -#define GST_TYPE_CD_PARANOIA_SRC (gst_cd_paranoia_src_get_type()) -#define GST_CD_PARANOIA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CD_PARANOIA_SRC,GstCdParanoiaSrc)) -#define GST_CD_PARANOIA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CD_PARANOIA_SRC,GstCdParanoiaSrcClass)) -#define GST_IS_CD_PARANOIA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CD_PARANOIA_SRC)) -#define GST_IS_CD_PARANOIA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CD_PARANOIA_SRC)) -#define GST_CD_PARANOIA_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CDDA_BASAE_SRC, GstCdParanoiaSrcClass)) - -typedef struct _GstCdParanoiaSrc GstCdParanoiaSrc; -typedef struct _GstCdParanoiaSrcClass GstCdParanoiaSrcClass; - -/** - * GstCdParanoiaSrc: - * - * The cdparanoia object structure. - */ -struct _GstCdParanoiaSrc { - GstCddaBaseSrc cddabasesrc; - - /*< private >*/ - cdrom_drive *d; - cdrom_paranoia *p; - - gint next_sector; /* -1 or next sector we expect to - * read, so we know when to do a seek */ - - gint paranoia_mode; - gint read_speed; - gint search_overlap; - - gchar *generic_device; -}; - -struct _GstCdParanoiaSrcClass { - GstCddaBaseSrcClass parent_class; - - /* signal callbacks */ - /** - * GstCdParanoiaSrcClass::transport-error: - * @src: the GstCddaBaseSrc source element object - * @sector: the sector at which the error happened - * - * This signal is emitted when a sector could not be read - * because of a transport error. - */ - void (*transport_error) (GstCdParanoiaSrc * src, gint sector); - /** - * GstCdParanoiaSrcClass::uncorrected-error: - * @src: the GstCddaBaseSrc source element object - * @sector: the sector at which the error happened - * - * This signal is emitted when a sector could not be read - * because of a transport error. - */ - void (*uncorrected_error) (GstCdParanoiaSrc * src, gint sector); -}; - -GType gst_cd_paranoia_src_get_type (void); - -G_END_DECLS - -#endif /* __GST_CD_PARANOIA_SRC_H__ */ - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgio.c --- a/gst_plugins_base/ext/gio/gstgio.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,214 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstgio.h" -#include "gstgiosink.h" -#include "gstgiosrc.h" -#include "gstgiostreamsink.h" -#include "gstgiostreamsrc.h" - -GST_DEBUG_CATEGORY_STATIC (gst_gio_debug); -#define GST_CAT_DEFAULT gst_gio_debug - -/* @func_name: Name of the GIO function, for debugging messages. - * @err: Error location. *err may be NULL, but err must be non-NULL. - * @ret: Flow return location. May be NULL. Is set to either #GST_FLOW_ERROR - * or #GST_FLOW_WRONG_STATE. - * - * Returns: TRUE to indicate a handled error. Error at given location err will - * be freed and *err will be set to NULL. A FALSE return indicates an unhandled - * error: The err location is unchanged and guaranteed to be != NULL. ret, if - * given, is set to GST_FLOW_ERROR. - */ -gboolean -gst_gio_error (gpointer element, const gchar * func_name, GError ** err, - GstFlowReturn * ret) -{ - gboolean handled = TRUE; - - if (ret) - *ret = GST_FLOW_ERROR; - - if (GST_GIO_ERROR_MATCHES (*err, CANCELLED)) { - GST_DEBUG_OBJECT (element, "blocking I/O call cancelled (%s)", func_name); - if (ret) - *ret = GST_FLOW_WRONG_STATE; - } else if (*err != NULL) { - handled = FALSE; - } else { - GST_ELEMENT_ERROR (element, LIBRARY, FAILED, (NULL), - ("%s call failed without error set", func_name)); - } - - if (handled) - g_clear_error (err); - - return handled; -} - -GstFlowReturn -gst_gio_seek (gpointer element, GSeekable * stream, guint64 offset, - GCancellable * cancel) -{ - gboolean success; - GstFlowReturn ret; - GError *err = NULL; - - GST_LOG_OBJECT (element, "seeking to offset %" G_GINT64_FORMAT, offset); - - success = g_seekable_seek (stream, offset, G_SEEK_SET, cancel, &err); - - if (success) - ret = GST_FLOW_OK; - else if (!gst_gio_error (element, "g_seekable_seek", &err, &ret)) { - GST_ELEMENT_ERROR (element, RESOURCE, SEEK, (NULL), - ("Could not seek: %s", err->message)); - g_clear_error (&err); - } - - return ret; -} - -static gchar ** -gst_gio_get_supported_protocols (void) -{ - return g_strdupv ((gchar **) - g_vfs_get_supported_uri_schemes (g_vfs_get_default ())); -} - -static GstURIType -gst_gio_uri_handler_get_type_sink (void) -{ - return GST_URI_SINK; -} - -static GstURIType -gst_gio_uri_handler_get_type_src (void) -{ - return GST_URI_SRC; -} - -static gchar ** -gst_gio_uri_handler_get_protocols (void) -{ - static gchar **protocols = NULL; - - if (!protocols) - protocols = gst_gio_get_supported_protocols (); - - return protocols; -} - -static const gchar * -gst_gio_uri_handler_get_uri (GstURIHandler * handler) -{ - GstElement *element = GST_ELEMENT (handler); - const gchar *uri; - - g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); - - g_object_get (G_OBJECT (element), "location", &uri, NULL); - - return uri; -} - -static gboolean -gst_gio_uri_handler_set_uri (GstURIHandler * handler, const gchar * uri) -{ - GstElement *element = GST_ELEMENT (handler); - - g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); - - if (GST_STATE (element) == GST_STATE_PLAYING || - GST_STATE (element) == GST_STATE_PAUSED) - return FALSE; - - g_object_set (G_OBJECT (element), "location", uri, NULL); - - return TRUE; -} - -static void -gst_gio_uri_handler_init (gpointer g_iface, gpointer iface_data) -{ - GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; - gboolean sink = GPOINTER_TO_INT (iface_data); /* See in do_init below. */ - - if (sink) - iface->get_type = gst_gio_uri_handler_get_type_sink; - else - iface->get_type = gst_gio_uri_handler_get_type_src; - iface->get_protocols = gst_gio_uri_handler_get_protocols; - iface->get_uri = gst_gio_uri_handler_get_uri; - iface->set_uri = gst_gio_uri_handler_set_uri; -} - -void -gst_gio_uri_handler_do_init (GType type) -{ - GInterfaceInfo uri_handler_info = { - gst_gio_uri_handler_init, - NULL, - NULL - }; - - /* Store information for uri_handler_init to use for distinguishing the - * element types. This lets us use a single interface implementation for both - * classes. */ - uri_handler_info.interface_data = GINT_TO_POINTER (g_type_is_a (type, - GST_TYPE_BASE_SINK)); - - g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &uri_handler_info); -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - gboolean ret = TRUE; - - GST_DEBUG_CATEGORY_INIT (gst_gio_debug, "gio", 0, "GIO elements"); - - /* FIXME: Rank is MARGINAL for now, should be at least SECONDARY+1 in the future - * to replace gnomevfssink/src. For testing purposes PRIMARY+1 one makes sense - * so it gets autoplugged and preferred over filesrc/sink. */ - - ret &= gst_element_register (plugin, "giosink", GST_RANK_MARGINAL, - GST_TYPE_GIO_SINK); - - ret &= gst_element_register (plugin, "giosrc", GST_RANK_MARGINAL, - GST_TYPE_GIO_SRC); - - ret &= gst_element_register (plugin, "giostreamsink", GST_RANK_NONE, - GST_TYPE_GIO_STREAM_SINK); - - ret &= gst_element_register (plugin, "giostreamsrc", GST_RANK_NONE, - GST_TYPE_GIO_STREAM_SRC); - - return ret; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "gio", - "GIO elements", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgio.h --- a/gst_plugins_base/ext/gio/gstgio.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_GIO_H__ -#define __GST_GIO_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_GIO_ERROR_MATCHES(err, code) g_error_matches (err, G_IO_ERROR, G_IO_ERROR_##code) - -#define GST_GIO_STREAM_IS_SEEKABLE(stream) (G_IS_SEEKABLE (stream) && g_seekable_can_seek (G_SEEKABLE (stream))) - -gboolean gst_gio_error (gpointer element, const gchar *func_name, - GError **err, GstFlowReturn *ret); -GstFlowReturn gst_gio_seek (gpointer element, GSeekable *stream, guint64 offset, - GCancellable *cancel); -void gst_gio_uri_handler_do_init (GType type); - -G_END_DECLS - -#endif /* __GST_GIO_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiobasesink.c --- a/gst_plugins_base/ext/gio/gstgiobasesink.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,349 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gstgiobasesink.h" - -GST_DEBUG_CATEGORY_STATIC (gst_gio_base_sink_debug); -#define GST_CAT_DEFAULT gst_gio_base_sink_debug - -static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -GST_BOILERPLATE (GstGioBaseSink, gst_gio_base_sink, GstBaseSink, - GST_TYPE_BASE_SINK); - -static void gst_gio_base_sink_finalize (GObject * object); -static gboolean gst_gio_base_sink_start (GstBaseSink * base_sink); -static gboolean gst_gio_base_sink_stop (GstBaseSink * base_sink); -static gboolean gst_gio_base_sink_unlock (GstBaseSink * base_sink); -static gboolean gst_gio_base_sink_unlock_stop (GstBaseSink * base_sink); -static gboolean gst_gio_base_sink_event (GstBaseSink * base_sink, - GstEvent * event); -static GstFlowReturn gst_gio_base_sink_render (GstBaseSink * base_sink, - GstBuffer * buffer); -static gboolean gst_gio_base_sink_query (GstPad * pad, GstQuery * query); - -static void -gst_gio_base_sink_base_init (gpointer gclass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - - GST_DEBUG_CATEGORY_INIT (gst_gio_base_sink_debug, "gio_base_sink", 0, - "GIO base sink"); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_factory)); -} - -static void -gst_gio_base_sink_class_init (GstGioBaseSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - - gobject_class->finalize = gst_gio_base_sink_finalize; - - gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_gio_base_sink_start); - gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_gio_base_sink_stop); - gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_gio_base_sink_unlock); - gstbasesink_class->unlock_stop = - GST_DEBUG_FUNCPTR (gst_gio_base_sink_unlock_stop); - gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_gio_base_sink_event); - gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_gio_base_sink_render); -} - -static void -gst_gio_base_sink_init (GstGioBaseSink * sink, GstGioBaseSinkClass * gclass) -{ - gst_pad_set_query_function (GST_BASE_SINK_PAD (sink), - GST_DEBUG_FUNCPTR (gst_gio_base_sink_query)); - - gst_base_sink_set_sync (GST_BASE_SINK (sink), FALSE); - - sink->cancel = g_cancellable_new (); -} - -static void -gst_gio_base_sink_finalize (GObject * object) -{ - GstGioBaseSink *sink = GST_GIO_BASE_SINK (object); - - if (sink->cancel) { - g_object_unref (sink->cancel); - sink->cancel = NULL; - } - - if (sink->stream) { - g_object_unref (sink->stream); - sink->stream = NULL; - } - - GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); -} - -static gboolean -gst_gio_base_sink_start (GstBaseSink * base_sink) -{ - GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink); - - if (!G_IS_OUTPUT_STREAM (sink->stream)) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), - ("No stream given yet")); - return FALSE; - } - - sink->position = 0; - - GST_DEBUG_OBJECT (sink, "started stream"); - - return TRUE; -} - -static gboolean -gst_gio_base_sink_stop (GstBaseSink * base_sink) -{ - GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink); - gboolean success; - GError *err = NULL; - - if (G_IS_OUTPUT_STREAM (sink->stream)) { - GST_DEBUG_OBJECT (sink, "closing stream"); - - /* FIXME: can block but unfortunately we can't use async operations - * here because they require a running main loop */ - success = g_output_stream_close (sink->stream, sink->cancel, &err); - - if (!success && !gst_gio_error (sink, "g_output_stream_close", &err, NULL)) { - GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL), - ("g_ooutput_stream_close failed: %s", err->message)); - g_clear_error (&err); - } else if (!success) { - GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL), - ("g_output_stream_close failed")); - } else { - GST_DEBUG_OBJECT (sink, "g_outut_stream_close succeeded"); - } - - g_object_unref (sink->stream); - sink->stream = NULL; - } - - return TRUE; -} - -static gboolean -gst_gio_base_sink_unlock (GstBaseSink * base_sink) -{ - GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink); - - GST_LOG_OBJECT (sink, "triggering cancellation"); - - g_cancellable_cancel (sink->cancel); - - return TRUE; -} - -static gboolean -gst_gio_base_sink_unlock_stop (GstBaseSink * base_sink) -{ - GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink); - - GST_LOG_OBJECT (sink, "resetting cancellable"); - - g_cancellable_reset (sink->cancel); - - return TRUE; -} - -static gboolean -gst_gio_base_sink_event (GstBaseSink * base_sink, GstEvent * event) -{ - GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink); - GstFlowReturn ret = GST_FLOW_OK; - - if (sink->stream == NULL) - return TRUE; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - if (G_IS_OUTPUT_STREAM (sink->stream)) { - GstFormat format; - gint64 offset; - - gst_event_parse_new_segment (event, NULL, NULL, &format, &offset, NULL, - NULL); - - if (format != GST_FORMAT_BYTES) { - GST_WARNING_OBJECT (sink, "ignored NEWSEGMENT event in %s format", - gst_format_get_name (format)); - break; - } - - if (GST_GIO_STREAM_IS_SEEKABLE (sink->stream)) { - ret = gst_gio_seek (sink, G_SEEKABLE (sink->stream), offset, - sink->cancel); - if (ret == GST_FLOW_OK) - sink->position = offset; - } else { - ret = GST_FLOW_NOT_SUPPORTED; - } - } - break; - - case GST_EVENT_EOS: - case GST_EVENT_FLUSH_START: - if (G_IS_OUTPUT_STREAM (sink->stream)) { - gboolean success; - GError *err = NULL; - - success = g_output_stream_flush (sink->stream, sink->cancel, &err); - - if (!success && !gst_gio_error (sink, "g_output_stream_flush", &err, - &ret)) { - GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), - ("flush failed: %s", err->message)); - g_clear_error (&err); - } - } - break; - - default: - break; - } - - return (ret == GST_FLOW_OK); -} - -static GstFlowReturn -gst_gio_base_sink_render (GstBaseSink * base_sink, GstBuffer * buffer) -{ - GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink); - gssize written; - gboolean success; - GError *err = NULL; - - g_return_val_if_fail (G_IS_OUTPUT_STREAM (sink->stream), GST_FLOW_ERROR); - - GST_LOG_OBJECT (sink, "writing %u bytes to offset %" G_GUINT64_FORMAT, - GST_BUFFER_SIZE (buffer), sink->position); - - written = g_output_stream_write (sink->stream, - GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), sink->cancel, &err); - - success = (written >= 0); - - if (G_UNLIKELY (success && written < GST_BUFFER_SIZE (buffer))) { - /* FIXME: Can this happen? Should we handle it gracefully? gnomevfssink - * doesn't... */ - GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), - ("Could not write to stream: (short write, only %" - G_GUINT64_FORMAT " bytes of %d bytes written)", - written, GST_BUFFER_SIZE (buffer))); - return GST_FLOW_ERROR; - } - - if (success) { - sink->position += written; - return GST_FLOW_OK; - - } else { - GstFlowReturn ret; - - if (!gst_gio_error (sink, "g_output_stream_write", &err, &ret)) { - GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), - ("Could not write to stream: %s", err->message)); - g_clear_error (&err); - } - - return ret; - } -} - -static gboolean -gst_gio_base_sink_query (GstPad * pad, GstQuery * query) -{ - GstGioBaseSink *sink = GST_GIO_BASE_SINK (GST_PAD_PARENT (pad)); - GstFormat format; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - gst_query_parse_position (query, &format, NULL); - switch (format) { - case GST_FORMAT_BYTES: - case GST_FORMAT_DEFAULT: - gst_query_set_position (query, GST_FORMAT_BYTES, sink->position); - return TRUE; - default: - return FALSE; - } - case GST_QUERY_FORMATS: - gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES); - return TRUE; - default: - return gst_pad_query_default (pad, query); - } -} - -void -gst_gio_base_sink_set_stream (GstGioBaseSink * sink, GOutputStream * stream) -{ - g_return_if_fail (G_IS_OUTPUT_STREAM (stream)); - g_return_if_fail ((GST_STATE (sink) != GST_STATE_PLAYING && - GST_STATE (sink) != GST_STATE_PAUSED)); - - if (G_IS_OUTPUT_STREAM (sink->stream)) { - gboolean success; - GError *err = NULL; - - GST_DEBUG_OBJECT (sink, "closing old stream"); - - /* FIXME: can block but unfortunately we can't use async operations - * here because they require a running main loop */ - success = g_output_stream_close (sink->stream, sink->cancel, &err); - - if (!success && !gst_gio_error (sink, "g_output_stream_close", &err, NULL)) { - GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL), - ("g_output_stream_close failed: %s", err->message)); - g_clear_error (&err); - } else if (!success) { - GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL), - ("g_output_stream_close failed")); - } else { - GST_DEBUG_OBJECT (sink, "g_output_stream_close succeeded"); - } - - g_object_unref (sink->stream); - sink->stream = NULL; - } - - sink->stream = stream; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiobasesink.h --- a/gst_plugins_base/ext/gio/gstgiobasesink.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_GIO_BASE_SINK_H__ -#define __GST_GIO_BASE_SINK_H__ - -#include "gstgio.h" - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_GIO_BASE_SINK \ - (gst_gio_base_sink_get_type()) -#define GST_GIO_BASE_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_BASE_SINK,GstGioBaseSink)) -#define GST_GIO_BASE_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_BASE_SINK,GstGioBaseSinkClass)) -#define GST_IS_GIO_BASE_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_BASE_SINK)) -#define GST_IS_GIO_BASE_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_BASE_SINK)) - -typedef struct _GstGioBaseSink GstGioBaseSink; -typedef struct _GstGioBaseSinkClass GstGioBaseSinkClass; - -struct _GstGioBaseSink -{ - GstBaseSink sink; - - GCancellable *cancel; - guint64 position; - GOutputStream *stream; -}; - -struct _GstGioBaseSinkClass -{ - GstBaseSinkClass parent_class; -}; - -GType gst_gio_base_sink_get_type (void); - -void gst_gio_base_sink_set_stream (GstGioBaseSink *sink, GOutputStream *stream); - -G_END_DECLS - -#endif /* __GST_GIO_BASE_SINK_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiobasesrc.c --- a/gst_plugins_base/ext/gio/gstgiobasesrc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,383 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gstgiobasesrc.h" - -GST_DEBUG_CATEGORY_STATIC (gst_gio_base_src_debug); -#define GST_CAT_DEFAULT gst_gio_base_src_debug - -static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -GST_BOILERPLATE (GstGioBaseSrc, gst_gio_base_src, GstBaseSrc, - GST_TYPE_BASE_SRC); - -static void gst_gio_base_src_finalize (GObject * object); -static gboolean gst_gio_base_src_start (GstBaseSrc * base_src); -static gboolean gst_gio_base_src_stop (GstBaseSrc * base_src); -static gboolean gst_gio_base_src_get_size (GstBaseSrc * base_src, - guint64 * size); -static gboolean gst_gio_base_src_is_seekable (GstBaseSrc * base_src); -static gboolean gst_gio_base_src_unlock (GstBaseSrc * base_src); -static gboolean gst_gio_base_src_unlock_stop (GstBaseSrc * base_src); -static gboolean gst_gio_base_src_check_get_range (GstBaseSrc * base_src); -static GstFlowReturn gst_gio_base_src_create (GstBaseSrc * base_src, - guint64 offset, guint size, GstBuffer ** buf); - -static void -gst_gio_base_src_base_init (gpointer gclass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - - GST_DEBUG_CATEGORY_INIT (gst_gio_base_src_debug, "gio_base_src", 0, - "GIO base source"); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_factory)); -} - -static void -gst_gio_base_src_class_init (GstGioBaseSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSrcClass *gstbasesrc_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesrc_class = (GstBaseSrcClass *) klass; - - gobject_class->finalize = gst_gio_base_src_finalize; - - gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gio_base_src_start); - gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_gio_base_src_stop); - gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_gio_base_src_get_size); - gstbasesrc_class->is_seekable = - GST_DEBUG_FUNCPTR (gst_gio_base_src_is_seekable); - gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_gio_base_src_unlock); - gstbasesrc_class->unlock_stop = - GST_DEBUG_FUNCPTR (gst_gio_base_src_unlock_stop); - gstbasesrc_class->check_get_range = - GST_DEBUG_FUNCPTR (gst_gio_base_src_check_get_range); - gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_gio_base_src_create); -} - -static void -gst_gio_base_src_init (GstGioBaseSrc * src, GstGioBaseSrcClass * gclass) -{ - src->cancel = g_cancellable_new (); -} - -static void -gst_gio_base_src_finalize (GObject * object) -{ - GstGioBaseSrc *src = GST_GIO_BASE_SRC (object); - - if (src->cancel) { - g_object_unref (src->cancel); - src->cancel = NULL; - } - - if (src->stream) { - g_object_unref (src->stream); - src->stream = NULL; - } - - GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); -} - -static gboolean -gst_gio_base_src_start (GstBaseSrc * base_src) -{ - GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src); - - if (!G_IS_INPUT_STREAM (src->stream)) { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), - ("No stream given yet")); - return FALSE; - } - - src->position = 0; - - GST_DEBUG_OBJECT (src, "started stream"); - - return TRUE; -} - -static gboolean -gst_gio_base_src_stop (GstBaseSrc * base_src) -{ - GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src); - gboolean success; - GError *err = NULL; - - if (G_IS_INPUT_STREAM (src->stream)) { - GST_DEBUG_OBJECT (src, "closing stream"); - - /* FIXME: can block but unfortunately we can't use async operations - * here because they require a running main loop */ - success = g_input_stream_close (src->stream, src->cancel, &err); - - if (!success && !gst_gio_error (src, "g_input_stream_close", &err, NULL)) { - GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL), - ("g_input_stream_close failed: %s", err->message)); - g_clear_error (&err); - } else if (!success) { - GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL), - ("g_input_stream_close failed")); - } else { - GST_DEBUG_OBJECT (src, "g_input_stream_close succeeded"); - } - - g_object_unref (src->stream); - src->stream = NULL; - } - - return TRUE; -} - -static gboolean -gst_gio_base_src_get_size (GstBaseSrc * base_src, guint64 * size) -{ - GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src); - - if (G_IS_FILE_INPUT_STREAM (src->stream)) { - GFileInfo *info; - GError *err = NULL; - - info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (src->stream), - G_FILE_ATTRIBUTE_STANDARD_SIZE, src->cancel, &err); - - if (info != NULL) { - *size = g_file_info_get_size (info); - g_object_unref (info); - GST_DEBUG_OBJECT (src, "found size: %" G_GUINT64_FORMAT, *size); - return TRUE; - } - - if (!gst_gio_error (src, "g_file_input_stream_query_info", &err, NULL)) { - - if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED)) - GST_DEBUG_OBJECT (src, "size information not available"); - else - GST_WARNING_OBJECT (src, "size information retrieval failed: %s", - err->message); - - g_clear_error (&err); - } - } else if (GST_GIO_STREAM_IS_SEEKABLE (src->stream)) { - goffset old; - goffset stream_size; - gboolean ret; - GSeekable *seekable = G_SEEKABLE (src->stream); - GError *err = NULL; - - old = g_seekable_tell (seekable); - - ret = g_seekable_seek (seekable, 0, G_SEEK_END, src->cancel, &err); - if (!ret) { - if (!gst_gio_error (src, "g_seekable_seek", &err, NULL)) { - if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED)) - GST_DEBUG_OBJECT (src, - "Seeking to the end of stream is not supported"); - else - GST_WARNING_OBJECT (src, "Seeking to end of stream failed: %s", - err->message); - g_clear_error (&err); - } else { - GST_WARNING_OBJECT (src, "Seeking to end of stream failed"); - } - - return FALSE; - } - - stream_size = g_seekable_tell (seekable); - - ret = g_seekable_seek (seekable, old, G_SEEK_SET, src->cancel, &err); - if (!ret) { - if (!gst_gio_error (src, "g_seekable_seek", &err, NULL)) { - if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED)) - GST_ERROR_OBJECT (src, "Seeking to the old position not supported"); - else - GST_ERROR_OBJECT (src, "Seeking to the old position failed: %s", - err->message); - g_clear_error (&err); - } else { - GST_ERROR_OBJECT (src, "Seeking to the old position faile"); - } - - return FALSE; - } - - if (stream_size >= 0) { - *size = stream_size; - return TRUE; - } - } - - return FALSE; -} - -static gboolean -gst_gio_base_src_is_seekable (GstBaseSrc * base_src) -{ - GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src); - gboolean seekable; - - seekable = GST_GIO_STREAM_IS_SEEKABLE (src->stream); - - GST_DEBUG_OBJECT (src, "can seek: %d", seekable); - - return seekable; -} - -static gboolean -gst_gio_base_src_unlock (GstBaseSrc * base_src) -{ - GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src); - - GST_LOG_OBJECT (src, "triggering cancellation"); - - g_cancellable_cancel (src->cancel); - - return TRUE; -} - -static gboolean -gst_gio_base_src_unlock_stop (GstBaseSrc * base_src) -{ - GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src); - - GST_LOG_OBJECT (src, "resetting cancellable"); - - g_cancellable_reset (src->cancel); - - return TRUE; -} - -static gboolean -gst_gio_base_src_check_get_range (GstBaseSrc * base_src) -{ - /* FIXME: Implement dry-run variant using guesswork like gnomevfssrc? */ - - return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_SRC_CLASS, - check_get_range, (base_src), FALSE); -} - -static GstFlowReturn -gst_gio_base_src_create (GstBaseSrc * base_src, guint64 offset, guint size, - GstBuffer ** buf_return) -{ - GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src); - GstBuffer *buf; - gssize read; - gboolean success, eos; - GstFlowReturn ret = GST_FLOW_OK; - GError *err = NULL; - - g_return_val_if_fail (G_IS_INPUT_STREAM (src->stream), GST_FLOW_ERROR); - - if (G_UNLIKELY (offset != src->position)) { - if (!GST_GIO_STREAM_IS_SEEKABLE (src->stream)) - return GST_FLOW_NOT_SUPPORTED; - - ret = gst_gio_seek (src, G_SEEKABLE (src->stream), offset, src->cancel); - - if (ret == GST_FLOW_OK) - src->position = offset; - else - return ret; - } - - buf = gst_buffer_new_and_alloc (size); - - GST_LOG_OBJECT (src, "reading %u bytes from offset %" G_GUINT64_FORMAT, - size, offset); - - read = - g_input_stream_read (G_INPUT_STREAM (src->stream), GST_BUFFER_DATA (buf), - size, src->cancel, &err); - - success = (read >= 0); - eos = (size > 0 && read == 0); - - if (!success && !gst_gio_error (src, "g_input_stream_read", &err, &ret)) { - GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), - ("Could not read from stream: %s", err->message)); - g_clear_error (&err); - } - - if (success && !eos) { - src->position += read; - GST_BUFFER_OFFSET (buf) = offset; - GST_BUFFER_SIZE (buf) = read; - *buf_return = buf; - } else { - /* !success || eos */ - gst_buffer_unref (buf); - } - - if (eos) - ret = GST_FLOW_UNEXPECTED; - - return ret; -} - -void -gst_gio_base_src_set_stream (GstGioBaseSrc * src, GInputStream * stream) -{ - gboolean success; - GError *err = NULL; - - g_return_if_fail (G_IS_INPUT_STREAM (stream)); - g_return_if_fail ((GST_STATE (src) != GST_STATE_PLAYING && - GST_STATE (src) != GST_STATE_PAUSED)); - - if (G_IS_INPUT_STREAM (src->stream)) { - GST_DEBUG_OBJECT (src, "closing old stream"); - - /* FIXME: can block but unfortunately we can't use async operations - * here because they require a running main loop */ - success = g_input_stream_close (src->stream, src->cancel, &err); - - if (!success && !gst_gio_error (src, "g_input_stream_close", &err, NULL)) { - GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL), - ("g_input_stream_close failed: %s", err->message)); - g_clear_error (&err); - } else if (!success) { - GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL), - ("g_input_stream_close failed")); - } else { - GST_DEBUG_OBJECT (src, "g_input_stream_close succeeded"); - } - - g_object_unref (src->stream); - src->stream = NULL; - } - - src->stream = stream; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiobasesrc.h --- a/gst_plugins_base/ext/gio/gstgiobasesrc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_GIO_BASE_SRC_H__ -#define __GST_GIO_BASE_SRC_H__ - -#include "gstgio.h" - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_GIO_BASE_SRC \ - (gst_gio_base_src_get_type()) -#define GST_GIO_BASE_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_BASE_SRC,GstGioBaseSrc)) -#define GST_GIO_BASE_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_BASE_SRC,GstGioBaseSrcClass)) -#define GST_IS_GIO_BASE_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_BASE_SRC)) -#define GST_IS_GIO_BASE_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_BASE_SRC)) - -typedef struct _GstGioBaseSrc GstGioBaseSrc; -typedef struct _GstGioBaseSrcClass GstGioBaseSrcClass; - -struct _GstGioBaseSrc -{ - GstBaseSrc src; - - GCancellable *cancel; - guint64 position; - GInputStream *stream; -}; - -struct _GstGioBaseSrcClass -{ - GstBaseSrcClass parent_class; -}; - -GType gst_gio_base_src_get_type (void); - -void gst_gio_base_src_set_stream (GstGioBaseSrc *src, GInputStream *stream); - -G_END_DECLS - -#endif /* __GST_GIO_BASE_SRC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiosink.c --- a/gst_plugins_base/ext/gio/gstgiosink.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,250 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -/** - * SECTION:element-giosink - * @short_description: Write a stream to any GIO-supported location - * @see_also: #GstFileSink, #GstGnomeVFSSink, #GstGioSrc - * - * - * - * This plugin writes incoming data to a local or remote location specified - * by an URI. This location can be specified using any protocol supported by - * the GIO library or it's VFS backends. Common protocols are 'file', 'ftp', - * or 'smb'. - * - * - * Example pipeline: - * - * gst-launch -v filesrc location=input.xyz ! giosink location=file:///home/joe/out.xyz - * - * The above pipeline will simply copy a local file. Instead of giosink, - * we could just as well have used the filesink element here. - * - * - * Another example pipeline: - * - * gst-launch -v filesrc location=foo.mp3 ! mad ! flacenc ! giosink location=smb://othercomputer/foo.flac - * - * The above pipeline will re-encode an mp3 file into FLAC format and store - * it on a remote host using the Samba protocol. - * - * - * Another example pipeline: - * - * gst-launch -v audiotestsrc num-buffers=100 ! vorbisenc ! oggmux ! giosink location=file:///home/foo/bar.ogg - * - * The above pipeline will encode a 440Hz sine wave to Ogg Vorbis and stores - * it in the home directory of user foo. - * - * - */ - -/* FIXME: We would like to mount the enclosing volume of an URL - * if it isn't mounted yet but this is possible async-only. - * Unfortunately this requires a running main loop from the - * default context and we can't guarantuee this! - * - * We would also like to do authentication while mounting. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gstgiosink.h" - -GST_DEBUG_CATEGORY_STATIC (gst_gio_sink_debug); -#define GST_CAT_DEFAULT gst_gio_sink_debug - -/* Filter signals and args */ -enum -{ - LAST_SIGNAL -}; - -enum -{ - ARG_0, - ARG_LOCATION -}; - -GST_BOILERPLATE_FULL (GstGioSink, gst_gio_sink, GstGioBaseSink, - GST_TYPE_GIO_BASE_SINK, gst_gio_uri_handler_do_init); - -static void gst_gio_sink_finalize (GObject * object); -static void gst_gio_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_gio_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static gboolean gst_gio_sink_start (GstBaseSink * base_sink); - -static void -gst_gio_sink_base_init (gpointer gclass) -{ - static GstElementDetails element_details = { - "GIO sink", - "Sink/File", - "Write to any GIO-supported location", - "Ren\xc3\xa9 Stadler , " - "Sebastian Dröge " - }; - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - - GST_DEBUG_CATEGORY_INIT (gst_gio_sink_debug, "gio_sink", 0, "GIO sink"); - - gst_element_class_set_details (element_class, &element_details); -} - -static void -gst_gio_sink_class_init (GstGioSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - - gobject_class->finalize = gst_gio_sink_finalize; - gobject_class->set_property = gst_gio_sink_set_property; - gobject_class->get_property = gst_gio_sink_get_property; - - g_object_class_install_property (gobject_class, ARG_LOCATION, - g_param_spec_string ("location", "Location", "URI location to write to", - NULL, G_PARAM_READWRITE)); - - gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_gio_sink_start); -} - -static void -gst_gio_sink_init (GstGioSink * sink, GstGioSinkClass * gclass) -{ -} - -static void -gst_gio_sink_finalize (GObject * object) -{ - GstGioSink *sink = GST_GIO_SINK (object); - - if (sink->location) { - g_free (sink->location); - sink->location = NULL; - } - - GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); -} - -static void -gst_gio_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstGioSink *sink = GST_GIO_SINK (object); - - switch (prop_id) { - case ARG_LOCATION: - if (GST_STATE (sink) == GST_STATE_PLAYING || - GST_STATE (sink) == GST_STATE_PAUSED) - break; - - g_free (sink->location); - sink->location = g_strdup (g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_gio_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstGioSink *sink = GST_GIO_SINK (object); - - switch (prop_id) { - case ARG_LOCATION: - g_value_set_string (value, sink->location); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gst_gio_sink_start (GstBaseSink * base_sink) -{ - GstGioSink *sink = GST_GIO_SINK (base_sink); - GFile *file; - GOutputStream *stream; - GCancellable *cancel = GST_GIO_BASE_SINK (sink)->cancel; - gboolean success; - GError *err = NULL; - - if (sink->location == NULL) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), - ("No location given")); - return FALSE; - } - - file = g_file_new_for_uri (sink->location); - - if (file == NULL) { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), - ("Malformed URI or protocol not supported (%s)", sink->location)); - return FALSE; - } - - stream = - G_OUTPUT_STREAM (g_file_create (file, G_FILE_CREATE_NONE, cancel, &err)); - - success = (stream != NULL); - - g_object_unref (file); - - if (!success && !gst_gio_error (sink, "g_file_create", &err, NULL)) { - - /*if (GST_GIO_ERROR_MATCHES (err, EXISTS)) */ - /* FIXME: Retry with replace if overwrite == TRUE! */ - - if (GST_GIO_ERROR_MATCHES (err, NOT_FOUND)) - GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, (NULL), - ("Could not open location %s for writing: %s", - sink->location, err->message)); - else - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ, (NULL), - ("Could not open location %s for writing: %s", - sink->location, err->message)); - - g_clear_error (&err); - } - - if (!success) - return FALSE; - - GST_DEBUG_OBJECT (sink, "opened location %s", sink->location); - - gst_gio_base_sink_set_stream (GST_GIO_BASE_SINK (sink), stream); - - return GST_BASE_SINK_CLASS (parent_class)->start (base_sink); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiosink.h --- a/gst_plugins_base/ext/gio/gstgiosink.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_GIO_SINK_H__ -#define __GST_GIO_SINK_H__ - -#include "gstgio.h" -#include "gstgiobasesink.h" - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_GIO_SINK \ - (gst_gio_sink_get_type()) -#define GST_GIO_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_SINK,GstGioSink)) -#define GST_GIO_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_SINK,GstGioSinkClass)) -#define GST_IS_GIO_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_SINK)) -#define GST_IS_GIO_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_SINK)) - -typedef struct _GstGioSink GstGioSink; -typedef struct _GstGioSinkClass GstGioSinkClass; - -/** - * GstGioSink: - * - * Opaque data structure. - */ -struct _GstGioSink -{ - GstGioBaseSink sink; - - /*< private >*/ - gchar *location; - - GMainLoop *loop; - gboolean mount_successful; -}; - -struct _GstGioSinkClass -{ - GstGioBaseSinkClass parent_class; -}; - -GType gst_gio_sink_get_type (void); - -G_END_DECLS - -#endif /* __GST_GIO_SINK_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiosrc.c --- a/gst_plugins_base/ext/gio/gstgiosrc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -/** - * SECTION:element-giosrc - * @short_description: Read from any GIO-supported location - * @see_also: #GstFileSrc, #GstGnomeVFSSrc, #GstGioSink - * - * - * - * This plugin reads data from a local or remote location specified - * by an URI. This location can be specified using any protocol supported by - * the GIO library or it's VFS backends. Common protocols are 'file', 'http', - * 'ftp', or 'smb'. - * - * - * Example pipeline: - * - * gst-launch -v giosrc location=file:///home/joe/foo.xyz ! fakesink - * - * The above pipeline will simply read a local file and do nothing with the - * data read. Instead of giosrc, we could just as well have used the - * filesrc element here. - * - * - * Another example pipeline: - * - * gst-launch -v giosrc location=smb://othercomputer/foo.xyz ! filesink location=/home/joe/foo.xyz - * - * The above pipeline will copy a file from a remote host to the local file - * system using the Samba protocol. - * - * - * Yet another example pipeline: - * - * gst-launch -v giosrc location=http://music.foobar.com/demo.mp3 ! mad ! audioconvert ! audioresample ! alsasink - * - * The above pipeline will read and decode and play an mp3 file from a - * web server using the http protocol. - * - * - */ - -/* FIXME: We would like to mount the enclosing volume of an URL - * if it isn't mounted yet but this is possible async-only. - * Unfortunately this requires a running main loop from the - * default context and we can't guarantuee this! - * - * We would also like to do authentication while mounting. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gstgiosrc.h" - -GST_DEBUG_CATEGORY_STATIC (gst_gio_src_debug); -#define GST_CAT_DEFAULT gst_gio_src_debug - -enum -{ - ARG_0, - ARG_LOCATION -}; - -GST_BOILERPLATE_FULL (GstGioSrc, gst_gio_src, GstGioBaseSrc, - GST_TYPE_GIO_BASE_SRC, gst_gio_uri_handler_do_init); - -static void gst_gio_src_finalize (GObject * object); -static void gst_gio_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_gio_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static gboolean gst_gio_src_start (GstBaseSrc * base_src); - -static void -gst_gio_src_base_init (gpointer gclass) -{ - static GstElementDetails element_details = { - "GIO source", - "Source/File", - "Read from any GIO-supported location", - "Ren\xc3\xa9 Stadler , " - "Sebastian Dröge " - }; - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - - GST_DEBUG_CATEGORY_INIT (gst_gio_src_debug, "gio_src", 0, "GIO source"); - - gst_element_class_set_details (element_class, &element_details); -} - -static void -gst_gio_src_class_init (GstGioSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSrcClass *gstbasesrc_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesrc_class = (GstBaseSrcClass *) klass; - - gobject_class->finalize = gst_gio_src_finalize; - gobject_class->set_property = gst_gio_src_set_property; - gobject_class->get_property = gst_gio_src_get_property; - - g_object_class_install_property (gobject_class, ARG_LOCATION, - g_param_spec_string ("location", "Location", "URI location to read from", - NULL, G_PARAM_READWRITE)); - - gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gio_src_start); -} - -static void -gst_gio_src_init (GstGioSrc * src, GstGioSrcClass * gclass) -{ -} - -static void -gst_gio_src_finalize (GObject * object) -{ - GstGioSrc *src = GST_GIO_SRC (object); - - if (src->location) { - g_free (src->location); - src->location = NULL; - } - - GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); -} - -static void -gst_gio_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstGioSrc *src = GST_GIO_SRC (object); - - switch (prop_id) { - case ARG_LOCATION: - if (GST_STATE (src) == GST_STATE_PLAYING || - GST_STATE (src) == GST_STATE_PAUSED) - break; - - g_free (src->location); - src->location = g_strdup (g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_gio_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstGioSrc *src = GST_GIO_SRC (object); - - switch (prop_id) { - case ARG_LOCATION: - g_value_set_string (value, src->location); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gst_gio_src_start (GstBaseSrc * base_src) -{ - GstGioSrc *src = GST_GIO_SRC (base_src); - GFile *file; - GError *err = NULL; - GInputStream *stream; - GCancellable *cancel = GST_GIO_BASE_SRC (src)->cancel; - - if (src->location == NULL) { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("No location given")); - return FALSE; - } - - file = g_file_new_for_uri (src->location); - - if (file == NULL) { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), - ("Malformed URI or protocol not supported (%s)", src->location)); - return FALSE; - } - - stream = G_INPUT_STREAM (g_file_read (file, cancel, &err)); - - g_object_unref (file); - - if (stream == NULL && !gst_gio_error (src, "g_file_read", &err, NULL)) { - - if (GST_GIO_ERROR_MATCHES (err, NOT_FOUND)) { - GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), - ("Could not open location %s for reading: %s", - src->location, err->message)); - } else { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), - ("Could not open location %s for reading: %s", - src->location, err->message)); - } - - g_clear_error (&err); - return FALSE; - } else if (stream == NULL) { - return FALSE; - } - - gst_gio_base_src_set_stream (GST_GIO_BASE_SRC (src), stream); - - GST_DEBUG_OBJECT (src, "opened location %s", src->location); - - return GST_BASE_SRC_CLASS (parent_class)->start (base_src); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiosrc.h --- a/gst_plugins_base/ext/gio/gstgiosrc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_GIO_SRC_H__ -#define __GST_GIO_SRC_H__ - -#include "gstgio.h" -#include "gstgiobasesrc.h" - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_GIO_SRC \ - (gst_gio_src_get_type()) -#define GST_GIO_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_SRC,GstGioSrc)) -#define GST_GIO_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_SRC,GstGioSrcClass)) -#define GST_IS_GIO_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_SRC)) -#define GST_IS_GIO_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_SRC)) - -typedef struct _GstGioSrc GstGioSrc; -typedef struct _GstGioSrcClass GstGioSrcClass; - -/** - * GstGioSrc: - * - * Opaque data structure. - */ -struct _GstGioSrc -{ - GstGioBaseSrc src; - - /*< private >*/ - gchar *location; - - GMainLoop *loop; - gboolean mount_successful; -}; - -struct _GstGioSrcClass -{ - GstGioBaseSrcClass parent_class; -}; - -GType gst_gio_src_get_type (void); - -G_END_DECLS - -#endif /* __GST_GIO_SRC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiostreamsink.c --- a/gst_plugins_base/ext/gio/gstgiostreamsink.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -/** - * SECTION:element-giostreamsink - * @short_description: Write to a GIO GOutputStream - * - * - * - * This plugin writes incoming data to a custom GIO #GOutputStream. - * - * - * It can, for example, be used to write a stream to memory with a - * #GMemoryOuputStream or to write to a file with a #GFileOuputStream. - * - * Example code - * - * The following example writes the received data to a #GMemoryOutputStream. - * - -#include <gst/gst.h> -#include <gio/gio.h> - -... - -GstElement *sink; -GMemoryOuputStream *stream; -// out_data will contain the received data -guint8 *out_data; - -... - -stream = G_MEMORY_OUTPUT_STREAM (g_memory_output_stream_new (NULL, 0, - (GReallocFunc) g_realloc, (GDestroyNotify) g_free)); -sink = gst_element_factory_make ("giostreamsink", "sink"); -g_object_set (G_OBJECT (sink), "stream", stream, NULL); - -... - -// after processing get the written data -out_data = g_memory_ouput_stream_get_data (G_MEMORY_OUTPUT_STREAM (stream)); - -... - - * - * - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gstgiostreamsink.h" - -GST_DEBUG_CATEGORY_STATIC (gst_gio_stream_sink_debug); -#define GST_CAT_DEFAULT gst_gio_stream_sink_debug - -/* Filter signals and args */ -enum -{ - LAST_SIGNAL -}; - -enum -{ - ARG_0, - ARG_STREAM -}; - -GST_BOILERPLATE (GstGioStreamSink, gst_gio_stream_sink, GstGioBaseSink, - GST_TYPE_GIO_BASE_SINK); - -static void gst_gio_stream_sink_finalize (GObject * object); -static void gst_gio_stream_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_gio_stream_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static void -gst_gio_stream_sink_base_init (gpointer gclass) -{ - static GstElementDetails element_details = { - "GIO stream sink", - "Sink", - "Write to any GIO stream", - "Sebastian Dröge " - }; - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - - GST_DEBUG_CATEGORY_INIT (gst_gio_stream_sink_debug, "gio_stream_sink", 0, - "GIO stream sink"); - - gst_element_class_set_details (element_class, &element_details); -} - -static void -gst_gio_stream_sink_class_init (GstGioStreamSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - - gobject_class->finalize = gst_gio_stream_sink_finalize; - gobject_class->set_property = gst_gio_stream_sink_set_property; - gobject_class->get_property = gst_gio_stream_sink_get_property; - - g_object_class_install_property (gobject_class, ARG_STREAM, - g_param_spec_object ("stream", "Stream", "Stream to write to", - G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE)); -} - -static void -gst_gio_stream_sink_init (GstGioStreamSink * sink, - GstGioStreamSinkClass * gclass) -{ -} - -static void -gst_gio_stream_sink_finalize (GObject * object) -{ - GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); -} - -static void -gst_gio_stream_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstGioStreamSink *sink = GST_GIO_STREAM_SINK (object); - - switch (prop_id) { - case ARG_STREAM:{ - GObject *stream; - - if (GST_STATE (sink) == GST_STATE_PLAYING || - GST_STATE (sink) == GST_STATE_PAUSED) - break; - - stream = g_value_dup_object (value); - if (G_IS_OUTPUT_STREAM (stream)) - gst_gio_base_sink_set_stream (GST_GIO_BASE_SINK (sink), - G_OUTPUT_STREAM (stream)); - - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_gio_stream_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstGioStreamSink *sink = GST_GIO_STREAM_SINK (object); - - switch (prop_id) { - case ARG_STREAM: - g_value_set_object (value, GST_GIO_BASE_SINK (sink)->stream); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiostreamsink.h --- a/gst_plugins_base/ext/gio/gstgiostreamsink.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_GIO_STREAM_SINK_H__ -#define __GST_GIO_STREAM_SINK_H__ - -#include "gstgio.h" -#include "gstgiobasesink.h" - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_GIO_STREAM_SINK \ - (gst_gio_stream_sink_get_type()) -#define GST_GIO_STREAM_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_STREAM_SINK,GstGioStreamSink)) -#define GST_GIO_STREAM_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_STREAM_SINK,GstGioStreamSinkClass)) -#define GST_IS_GIO_STREAM_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_STREAM_SINK)) -#define GST_IS_GIO_STREAM_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_STREAM_SINK)) - -typedef struct _GstGioStreamSink GstGioStreamSink; -typedef struct _GstGioStreamSinkClass GstGioStreamSinkClass; - -/** - * GstGioStreamSink: - * - * Opaque data structure. - */ -struct _GstGioStreamSink -{ - GstGioBaseSink sink; -}; - -struct _GstGioStreamSinkClass -{ - GstGioBaseSinkClass parent_class; -}; - -GType gst_gio_stream_sink_get_type (void); - -G_END_DECLS - -#endif /* __GST_GIO_STREAM_SINK_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiostreamsrc.c --- a/gst_plugins_base/ext/gio/gstgiostreamsrc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -/** - * SECTION:element-giostreamsrc - * @short_description: Reads data from a GIO GInputStream - * - * - * - * This plugin reads data from a custom GIO #GInputStream. - * - * - * It can, for example, be used to read data from memory with a - * #GMemoryInputStream or to read from a file with a - * #GFileInputStream. - * - * Example code - * - * The following example reads data from a #GMemoryOutputStream. - * - -#include <gst/gst.h> -#include <gio/gio.h> - -... - -GstElement *src; -GMemoryInputStream *stream; -// in_data will contain the data to send -guint8 *in_data; -gint i; - -... -in_data = g_new (guint8, 512); -for (i = 0; i < 512; i++) - in_data[i] = i % 256; - -stream = G_MEMORY_INPUT_STREAM (g_memory_input_stream_new_from_data (in_data, 512, - (GDestroyNotify) g_free)); -src = gst_element_factory_make ("giostreamsrc", "src"); -g_object_set (G_OBJECT (src), "stream", stream, NULL); - -... - - * - * - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gstgiostreamsrc.h" - -GST_DEBUG_CATEGORY_STATIC (gst_gio_stream_src_debug); -#define GST_CAT_DEFAULT gst_gio_stream_src_debug - -enum -{ - ARG_0, - ARG_STREAM -}; - -GST_BOILERPLATE (GstGioStreamSrc, gst_gio_stream_src, GstGioBaseSrc, - GST_TYPE_GIO_BASE_SRC); - -static void gst_gio_stream_src_finalize (GObject * object); -static void gst_gio_stream_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_gio_stream_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static void -gst_gio_stream_src_base_init (gpointer gclass) -{ - static GstElementDetails element_details = { - "GIO stream source", - "Source", - "Read from any GIO stream", - "Sebastian Dröge " - }; - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - - GST_DEBUG_CATEGORY_INIT (gst_gio_stream_src_debug, "gio_stream_src", 0, - "GIO source"); - - gst_element_class_set_details (element_class, &element_details); -} - -static void -gst_gio_stream_src_class_init (GstGioStreamSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSrcClass *gstbasesrc_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesrc_class = (GstBaseSrcClass *) klass; - - gobject_class->finalize = gst_gio_stream_src_finalize; - gobject_class->set_property = gst_gio_stream_src_set_property; - gobject_class->get_property = gst_gio_stream_src_get_property; - - g_object_class_install_property (gobject_class, ARG_STREAM, - g_param_spec_object ("stream", "Stream", "Stream to read from", - G_TYPE_INPUT_STREAM, G_PARAM_READWRITE)); -} - -static void -gst_gio_stream_src_init (GstGioStreamSrc * src, GstGioStreamSrcClass * gclass) -{ -} - -static void -gst_gio_stream_src_finalize (GObject * object) -{ - GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); -} - -static void -gst_gio_stream_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstGioStreamSrc *src = GST_GIO_STREAM_SRC (object); - - switch (prop_id) { - case ARG_STREAM:{ - GObject *stream; - - if (GST_STATE (src) == GST_STATE_PLAYING || - GST_STATE (src) == GST_STATE_PAUSED) - break; - - stream = g_value_dup_object (value); - if (G_IS_INPUT_STREAM (stream)) - gst_gio_base_src_set_stream (GST_GIO_BASE_SRC (src), - G_INPUT_STREAM (stream)); - - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_gio_stream_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstGioStreamSrc *src = GST_GIO_STREAM_SRC (object); - - switch (prop_id) { - case ARG_STREAM: - g_value_set_object (value, GST_GIO_BASE_SRC (src)->stream); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gio/gstgiostreamsrc.h --- a/gst_plugins_base/ext/gio/gstgiostreamsrc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2007 Rene Stadler - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_GIO_STREAM_SRC_H__ -#define __GST_GIO_STREAM_SRC_H__ - -#include "gstgio.h" -#include "gstgiobasesrc.h" - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_GIO_STREAM_SRC \ - (gst_gio_stream_src_get_type()) -#define GST_GIO_STREAM_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_STREAM_SRC,GstGioStreamSrc)) -#define GST_GIO_STREAM_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_STREAM_SRC,GstGioStreamSrcClass)) -#define GST_IS_GIO_STREAM_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_STREAM_SRC)) -#define GST_IS_GIO_STREAM_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_STREAM_SRC)) - -typedef struct _GstGioStreamSrc GstGioStreamSrc; -typedef struct _GstGioStreamSrcClass GstGioStreamSrcClass; - -/** - * GstGioStreamSrc: - * - * Opaque data structure. - */ -struct _GstGioStreamSrc -{ - GstGioBaseSrc src; -}; - -struct _GstGioStreamSrcClass -{ - GstGioBaseSrcClass parent_class; -}; - -GType gst_gio_stream_src_get_type (void); - -G_END_DECLS - -#endif /* __GST_GIO_STREAM_SRC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gnomevfs/gstgnomevfs.c --- a/gst_plugins_base/ext/gnomevfs/gstgnomevfs.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/* GStreamer - * Copyright (C) 2003 Benjamin Otte - * - * gnomevfs.c: register gnomevfs elements - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "gst/gst-i18n-plugin.h" - -#include "gstgnomevfs.h" -#include "gstgnomevfssrc.h" -#include "gstgnomevfssink.h" - -#include -#include - -#include - -gchar * -gst_gnome_vfs_location_to_uri_string (const gchar * location) -{ - gchar *newloc, *ret; - - if (location == NULL) - return NULL; - - /* already an URI string? */ - if (strstr (location, "://")) - return g_strdup (location); - - newloc = gnome_vfs_escape_path_string (location); - - if (newloc && *newloc == '/') { - ret = g_strdup_printf ("file://%s", newloc); - } else { - gchar *curdir; - - curdir = g_get_current_dir (); - ret = g_strdup_printf ("file://%s/%s", curdir, newloc); - g_free (curdir); - } - - g_free (newloc); - return ret; -} - -GType -gst_gnome_vfs_uri_get_type (void) -{ - static GType type; /* 0 */ - - if (type == 0) { - type = g_boxed_type_register_static ("GnomeVFSURI", - (GBoxedCopyFunc) gnome_vfs_uri_ref, - (GBoxedFreeFunc) gnome_vfs_uri_unref); - } - - return type; -} - -static gpointer -gst_gnome_vfs_handle_copy (gpointer handle) -{ - return handle; -} - -static void -gst_gnome_vfs_handle_free (gpointer handle) -{ - return; -} - -GType -gst_gnome_vfs_handle_get_type (void) -{ - static GType type; /* 0 */ - - if (type == 0) { - /* hackish, but makes it show up nicely in gst-inspect */ - type = g_boxed_type_register_static ("GnomeVFSHandle", - (GBoxedCopyFunc) gst_gnome_vfs_handle_copy, - (GBoxedFreeFunc) gst_gnome_vfs_handle_free); - } - - return type; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - /* gnome vfs engine init */ - if (!gnome_vfs_initialized ()) { - if (!gnome_vfs_init ()) { - GST_WARNING ("Failed to initialize GnomeVFS - not registering plugin!"); - return FALSE; - } - } - - if (!gst_element_register (plugin, "gnomevfssrc", GST_RANK_SECONDARY, - gst_gnome_vfs_src_get_type ())) - return FALSE; - - if (!gst_element_register (plugin, "gnomevfssink", GST_RANK_SECONDARY, - gst_gnome_vfs_sink_get_type ())) - return FALSE; - -#ifdef ENABLE_NLS -/* FIXME: add category - GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE, LOCALEDIR); - */ - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); -#endif /* ENABLE_NLS */ - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "gnomevfs", - "elements to read from and write to Gnome-VFS uri's", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gnomevfs/gstgnomevfs.h --- a/gst_plugins_base/ext/gnomevfs/gstgnomevfs.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* GStreamer - * Copyright (C) 2003 Benjamin Otte - * - * 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. - */ - - -#ifndef __GST_GNOME_VFS_H__ -#define __GST_GNOME_VFS_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_GNOME_VFS_URI (gst_gnome_vfs_uri_get_type ()) -#define GST_TYPE_GNOME_VFS_HANDLE (gst_gnome_vfs_handle_get_type ()) - -GType gst_gnome_vfs_uri_get_type (void); -GType gst_gnome_vfs_handle_get_type (void); - -gchar * gst_gnome_vfs_location_to_uri_string (const gchar * location); - -G_END_DECLS - -#endif /* __GST_GNOME_VFS_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gnomevfs/gstgnomevfssink.c --- a/gst_plugins_base/ext/gnomevfs/gstgnomevfssink.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,641 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * 2001 Bastien Nocera - * 2003 Colin Walters - * 2005 Tim-Philipp Müller - * - * gstgnomevfssink.c: - * - * 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. - */ - -/** - * SECTION:element-gnomevfssink - * @short_description: Write a stream to a GnomeVFS URI - * @see_also: #GstFileSink, #GstGnomeVFSSrc - * - * - * - * This plugin writes incoming data to a local or remote location specified - * by an URI. This location can be specified using any protocol supported by - * the GnomeVFS library. Common protocols are 'file', 'ftp', or 'smb'. - * - * - * Example pipeline: - * - * gst-launch -v filesrc location=input.xyz ! gnomevfssink location=file:///home/joe/out.xyz - * - * The above pipeline will simply copy a local file. Instead of gnomevfssink, - * we could just as well have used the filesink element here. - * - * - * Another example pipeline: - * - * gst-launch -v filesrc location=foo.mp3 ! mad ! flacenc ! gnomevfssink location=smb://othercomputer/foo.flac - * - * The above pipeline will re-encode an mp3 file into FLAC format and store - * it on a remote host using the Samba protocol. - * - * - * Applications can connect to the allow-overwrite signal to receive a callback when an - * existing file will be overwritten. The return value of the signal will determine if - * gnomevfssink will overwrite the resource or abort with an error. - * - * - * - * Last reviewed on 2006-02-28 (0.10.4) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstgnomevfssink.h" - -#include "gst/gst-i18n-plugin.h" - -#include -#include -#include -#include - -static const GstElementDetails gst_gnome_vfs_sink_details = -GST_ELEMENT_DETAILS ("GnomeVFS Sink", - "Sink/File", - "Write a stream to a GnomeVFS URI", - "Bastien Nocera "); - -enum -{ - SIGNAL_ERASE_ASK, - LAST_SIGNAL -}; - -enum -{ - ARG_0, - ARG_LOCATION, - ARG_URI, - ARG_HANDLE -}; - -static void gst_gnome_vfs_sink_finalize (GObject * obj); - -static void gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface, - gpointer iface_data); - -static void gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static gboolean gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink); -static void gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink); -static gboolean gst_gnome_vfs_sink_start (GstBaseSink * basesink); -static gboolean gst_gnome_vfs_sink_stop (GstBaseSink * basesink); -static GstFlowReturn gst_gnome_vfs_sink_render (GstBaseSink * basesink, - GstBuffer * buffer); -static gboolean gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink, - GstEvent * event); -static gboolean gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query); - -static guint gst_gnome_vfs_sink_signals[LAST_SIGNAL]; /* all 0 */ - -static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -GST_DEBUG_CATEGORY_STATIC (gst_gnome_vfs_sink_debug); -#define GST_CAT_DEFAULT gst_gnome_vfs_sink_debug - -static void -gst_gnome_vfs_sink_do_init (GType type) -{ - static const GInterfaceInfo urihandler_info = { - gst_gnome_vfs_sink_uri_handler_init, - NULL, - NULL - }; - - g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info); - - GST_DEBUG_CATEGORY_INIT (gst_gnome_vfs_sink_debug, "gnomevfssink", 0, - "Gnome VFS sink element"); -} - -GST_BOILERPLATE_FULL (GstGnomeVFSSink, gst_gnome_vfs_sink, GstBaseSink, - GST_TYPE_BASE_SINK, gst_gnome_vfs_sink_do_init); - -static void -gst_gnome_vfs_sink_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sinktemplate)); - - gst_element_class_set_details (element_class, &gst_gnome_vfs_sink_details); -} - -static gboolean -_gst_boolean_allow_overwrite_accumulator (GSignalInvocationHint * ihint, - GValue * return_accu, const GValue * handler_return, gpointer dummy) -{ - gboolean allow_overwrite; - - allow_overwrite = g_value_get_boolean (handler_return); - if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP)) - g_value_set_boolean (return_accu, allow_overwrite); - - /* stop emission if signal doesn't allow overwriting */ - return allow_overwrite; -} - -static void -gst_gnome_vfs_sink_class_init (GstGnomeVFSSinkClass * klass) -{ - GstBaseSinkClass *basesink_class; - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - basesink_class = (GstBaseSinkClass *) klass; - - gobject_class->set_property = gst_gnome_vfs_sink_set_property; - gobject_class->get_property = gst_gnome_vfs_sink_get_property; - gobject_class->finalize = gst_gnome_vfs_sink_finalize; - - g_object_class_install_property (gobject_class, ARG_LOCATION, - g_param_spec_string ("location", "File Location", - "Location of the file to write", NULL, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_URI, - g_param_spec_boxed ("uri", "GnomeVFSURI", "URI for GnomeVFS", - GST_TYPE_GNOME_VFS_URI, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_HANDLE, - g_param_spec_boxed ("handle", - "GnomeVFSHandle", "Handle for GnomeVFS", - GST_TYPE_GNOME_VFS_HANDLE, G_PARAM_READWRITE)); - - /** - * GstGnomeVFSSink::allow-overwrite - * @sink: the object which received the signal - * @uri: the URI to be overwritten - * - * This signal is fired when gnomevfssink is about to overwrite an - * existing resource. The application can connect to this signal and ask - * the user if the resource may be overwritten. - * - * Returns: A boolean indicating that the resource may be overwritten. - */ - gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK] = - g_signal_new ("allow-overwrite", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_CLEANUP, G_STRUCT_OFFSET (GstGnomeVFSSinkClass, erase_ask), - _gst_boolean_allow_overwrite_accumulator, NULL, - gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_GNOME_VFS_URI); - - basesink_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_stop); - basesink_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_start); - basesink_class->event = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_handle_event); - basesink_class->render = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_render); - basesink_class->get_times = NULL; -} - -static void -gst_gnome_vfs_sink_finalize (GObject * obj) -{ - GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (obj); - - if (sink->uri) { - gnome_vfs_uri_unref (sink->uri); - sink->uri = NULL; - } - - if (sink->uri_name) { - g_free (sink->uri_name); - sink->uri_name = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static void -gst_gnome_vfs_sink_init (GstGnomeVFSSink * sink, GstGnomeVFSSinkClass * klass) -{ - gst_pad_set_query_function (GST_BASE_SINK_PAD (sink), - GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_query)); - - sink->uri = NULL; - sink->uri_name = NULL; - sink->handle = NULL; - sink->own_handle = FALSE; - sink->current_pos = 0; - - GST_BASE_SINK (sink)->sync = FALSE; -} - -static void -gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstGnomeVFSSink *sink; - GstState cur_state; - - sink = GST_GNOME_VFS_SINK (object); - - gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0); - - if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) { - GST_WARNING_OBJECT (sink, "cannot set property when PAUSED or PLAYING"); - return; - } - - GST_OBJECT_LOCK (sink); - - switch (prop_id) { - case ARG_LOCATION:{ - const gchar *new_location; - - if (sink->uri) { - gnome_vfs_uri_unref (sink->uri); - sink->uri = NULL; - } - if (sink->uri_name) { - g_free (sink->uri_name); - sink->uri_name = NULL; - } - - new_location = g_value_get_string (value); - if (new_location) { - sink->uri_name = gst_gnome_vfs_location_to_uri_string (new_location); - sink->uri = gnome_vfs_uri_new (sink->uri_name); - } - break; - } - case ARG_URI:{ - if (sink->uri) { - gnome_vfs_uri_unref (sink->uri); - sink->uri = NULL; - } - if (sink->uri_name) { - g_free (sink->uri_name); - sink->uri_name = NULL; - } - if (g_value_get_boxed (value)) { - sink->uri = (GnomeVFSURI *) g_value_dup_boxed (value); - sink->uri_name = gnome_vfs_uri_to_string (sink->uri, 0); - } - break; - } - case ARG_HANDLE:{ - if (sink->uri) { - gnome_vfs_uri_unref (sink->uri); - sink->uri = NULL; - } - if (sink->uri_name) { - g_free (sink->uri_name); - sink->uri_name = NULL; - } - sink->handle = g_value_get_boxed (value); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - GST_OBJECT_UNLOCK (sink); -} - -static void -gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstGnomeVFSSink *sink; - - sink = GST_GNOME_VFS_SINK (object); - - GST_OBJECT_LOCK (sink); - - switch (prop_id) { - case ARG_LOCATION: - g_value_set_string (value, sink->uri_name); - break; - case ARG_URI: - g_value_set_boxed (value, sink->uri); - break; - case ARG_HANDLE: - g_value_set_boxed (value, sink->handle); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - GST_OBJECT_UNLOCK (sink); -} - -static gboolean -gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink) -{ - GnomeVFSResult result; - - if (sink->uri) { - /* open the file, all permissions, umask will apply */ - result = gnome_vfs_create_uri (&(sink->handle), sink->uri, - GNOME_VFS_OPEN_WRITE, TRUE, - GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE | - GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE | - GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE); - - /* if the file existed and the property says to ask, then ask! */ - if (result == GNOME_VFS_ERROR_FILE_EXISTS) { - gboolean erase_anyway = FALSE; - - g_signal_emit (G_OBJECT (sink), - gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK], 0, sink->uri, - &erase_anyway); - if (erase_anyway) { - result = gnome_vfs_create_uri (&(sink->handle), sink->uri, - GNOME_VFS_OPEN_WRITE, FALSE, - GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE | - GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE | - GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE); - } - } - - GST_DEBUG_OBJECT (sink, "open: %s", gnome_vfs_result_to_string (result)); - - if (result != GNOME_VFS_OK) { - gchar *filename = gnome_vfs_uri_to_string (sink->uri, - GNOME_VFS_URI_HIDE_PASSWORD); - - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - (_("Could not open vfs file \"%s\" for writing: %s."), - filename, gnome_vfs_result_to_string (result)), GST_ERROR_SYSTEM); - g_free (filename); - return FALSE; - } - sink->own_handle = TRUE; - } else if (!sink->handle) { - GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (_("No filename given")), - (NULL)); - return FALSE; - } else { - sink->own_handle = FALSE; - } - - sink->current_pos = 0; - - return TRUE; -} - -static void -gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink) -{ - GnomeVFSResult result; - - if (sink->own_handle) { - /* close the file */ - result = gnome_vfs_close (sink->handle); - - if (result != GNOME_VFS_OK) { - gchar *filename = gnome_vfs_uri_to_string (sink->uri, - GNOME_VFS_URI_HIDE_PASSWORD); - - GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE, - (_("Could not close vfs file \"%s\"."), filename), GST_ERROR_SYSTEM); - g_free (filename); - } - - sink->own_handle = FALSE; - sink->handle = NULL; - } -} - -static gboolean -gst_gnome_vfs_sink_start (GstBaseSink * basesink) -{ - gboolean ret; - - ret = gst_gnome_vfs_sink_open_file (GST_GNOME_VFS_SINK (basesink)); - - return ret; -} - -static gboolean -gst_gnome_vfs_sink_stop (GstBaseSink * basesink) -{ - GST_DEBUG_OBJECT (basesink, "closing ..."); - gst_gnome_vfs_sink_close_file (GST_GNOME_VFS_SINK (basesink)); - return TRUE; -} - -static gboolean -gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink, GstEvent * event) -{ - GstGnomeVFSSink *sink; - gboolean ret = TRUE; - - sink = GST_GNOME_VFS_SINK (basesink); - - GST_DEBUG_OBJECT (sink, "processing %s event", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT:{ - GnomeVFSResult res; - GstFormat format; - gint64 offset; - - gst_event_parse_new_segment (event, NULL, NULL, &format, &offset, - NULL, NULL); - - if (format != GST_FORMAT_BYTES) { - GST_WARNING_OBJECT (sink, "ignored NEWSEGMENT event in %s format", - gst_format_get_name (format)); - break; - } - - GST_LOG_OBJECT (sink, "seeking to offset %" G_GINT64_FORMAT, offset); - res = gnome_vfs_seek (sink->handle, GNOME_VFS_SEEK_START, offset); - - if (res != GNOME_VFS_OK) { - GST_ERROR_OBJECT (sink, "Failed to seek to offset %" - G_GINT64_FORMAT ": %s", offset, gnome_vfs_result_to_string (res)); - ret = FALSE; - } else { - sink->current_pos = offset; - } - - break; - } - - case GST_EVENT_FLUSH_START: - case GST_EVENT_EOS:{ - /* No need to flush with GnomeVfs */ - break; - } - default: - break; - } - - return ret; -} - -static gboolean -gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query) -{ - GstGnomeVFSSink *sink; - GstFormat format; - - sink = GST_GNOME_VFS_SINK (GST_PAD_PARENT (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - gst_query_parse_position (query, &format, NULL); - switch (format) { - case GST_FORMAT_DEFAULT: - case GST_FORMAT_BYTES: - gst_query_set_position (query, GST_FORMAT_BYTES, sink->current_pos); - return TRUE; - default: - return FALSE; - } - - case GST_QUERY_FORMATS: - gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES); - return TRUE; - - default: - return gst_pad_query_default (pad, query); - } -} - -static GstFlowReturn -gst_gnome_vfs_sink_render (GstBaseSink * basesink, GstBuffer * buf) -{ - GnomeVFSFileSize written, cur_pos; - GstGnomeVFSSink *sink; - GnomeVFSResult result; - GstFlowReturn ret; - - sink = GST_GNOME_VFS_SINK (basesink); - - if (gnome_vfs_tell (sink->handle, &cur_pos) == GNOME_VFS_OK) { - /* bring up to date with current position for proper reporting */ - sink->current_pos = cur_pos; - } - - result = gnome_vfs_write (sink->handle, GST_BUFFER_DATA (buf), - GST_BUFFER_SIZE (buf), &written); - - switch (result) { - case GNOME_VFS_OK:{ - GST_DEBUG_OBJECT (sink, "wrote %" G_GINT64_FORMAT " bytes at %" - G_GINT64_FORMAT, (gint64) written, (gint64) cur_pos); - - if (written < GST_BUFFER_SIZE (buf)) { - /* FIXME: what to do here? (tpm) */ - g_warning ("%s: %d bytes should be written, only %" - G_GUINT64_FORMAT " bytes written", G_STRLOC, - GST_BUFFER_SIZE (buf), written); - } - - sink->current_pos += GST_BUFFER_SIZE (buf); - ret = GST_FLOW_OK; - break; - } - case GNOME_VFS_ERROR_NO_SPACE:{ - /* TODO: emit signal/send msg on out-of-diskspace and - * handle this gracefully (see open bug) (tpm) */ - GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL), - ("bufsize=%u, written=%u", GST_BUFFER_SIZE (buf), (guint) written)); - ret = GST_FLOW_ERROR; - break; - } - default:{ - gchar *filename = gnome_vfs_uri_to_string (sink->uri, - GNOME_VFS_URI_HIDE_PASSWORD); - - GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, - (_("Error while writing to file \"%s\"."), filename), - ("%s, bufsize=%u, written=%u", gnome_vfs_result_to_string (result), - GST_BUFFER_SIZE (buf), (guint) written)); - - g_free (filename); - ret = GST_FLOW_ERROR; - break; - } - } - - return GST_FLOW_OK; -} - -/*** GSTURIHANDLER INTERFACE *************************************************/ - -static GstURIType -gst_gnome_vfs_sink_uri_get_type (void) -{ - return GST_URI_SINK; -} - -static gchar ** -gst_gnome_vfs_sink_uri_get_protocols (void) -{ - static gchar **protocols = NULL; - - if (!protocols) - protocols = gst_gnomevfs_get_supported_uris (); - - return protocols; -} - -static const gchar * -gst_gnome_vfs_sink_uri_get_uri (GstURIHandler * handler) -{ - GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler); - - return sink->uri_name; -} - -static gboolean -gst_gnome_vfs_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri) -{ - GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler); - GstState cur_state; - - gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0); - - if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) { - GST_WARNING_OBJECT (sink, "cannot set uri when PAUSED or PLAYING"); - return FALSE; - } - - g_object_set (sink, "location", uri, NULL); - - return TRUE; -} - -static void -gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface, gpointer iface_data) -{ - GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; - - iface->get_type = gst_gnome_vfs_sink_uri_get_type; - iface->get_protocols = gst_gnome_vfs_sink_uri_get_protocols; - iface->get_uri = gst_gnome_vfs_sink_uri_get_uri; - iface->set_uri = gst_gnome_vfs_sink_uri_set_uri; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gnomevfs/gstgnomevfssink.h --- a/gst_plugins_base/ext/gnomevfs/gstgnomevfssink.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * 2001 Bastien Nocera - * 2003 Colin Walters - * 2005 Tim-Philipp Müller - * - * 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. - */ - -#ifndef __GST_GNOME_VFS_SINK_H__ -#define __GST_GNOME_VFS_SINK_H__ - -#include "gstgnomevfs.h" -#include "gstgnomevfsuri.h" -#include - -G_BEGIN_DECLS - -#define GST_TYPE_GNOME_VFS_SINK \ - (gst_gnome_vfs_sink_get_type()) -#define GST_GNOME_VFS_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GNOME_VFS_SINK,GstGnomeVFSSink)) -#define GST_GNOME_VFS_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GNOME_VFS_SINK,GstGnomeVFSSinkClass)) -#define GST_IS_GNOME_VFS_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GNOME_VFS_SINK)) -#define GST_IS_GNOME_VFS_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GNOME_VFS_SINK)) - -typedef struct _GstGnomeVFSSink GstGnomeVFSSink; -typedef struct _GstGnomeVFSSinkClass GstGnomeVFSSinkClass; - -/** - * GstGnomeVFSSink: - * - * Opaque data structure. - */ -struct _GstGnomeVFSSink -{ - GstBaseSink basesink; - - /*< private >*/ - - /* uri */ - GnomeVFSURI *uri; - gchar *uri_name; - - /* handle */ - GnomeVFSHandle *handle; - - /* whether we opened the handle ourselves */ - gboolean own_handle; - - guint64 current_pos; -}; - -struct _GstGnomeVFSSinkClass -{ - GstBaseSinkClass basesink_class; - - /* signals */ - gboolean (*erase_ask) (GstElement * element, GnomeVFSURI * uri); -}; - -GType gst_gnome_vfs_sink_get_type (void); - -G_END_DECLS - -#endif /* __GST_GNOME_VFS_SINK_H__ */ - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gnomevfs/gstgnomevfssrc.c --- a/gst_plugins_base/ext/gnomevfs/gstgnomevfssrc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,880 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * 2001 Bastien Nocera - * 2002 Kristian Rietveld - * 2002,2003 Colin Walters - * - * gnomevfssrc.c: - * - * 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. - */ - -/** - * SECTION:element-gnomevfssrc - * @short_description: Read from any GnomeVFS-supported location - * @see_also: #GstFileSrc, #GstGnomeVFSSink - * - * - * - * This plugin reads data from a local or remote location specified - * by an URI. This location can be specified using any protocol supported by - * the GnomeVFS library. Common protocols are 'file', 'http', 'ftp', or 'smb'. - * - * - * In case the element-gnomevfssrc::iradio-mode property is set and the - * location is a http resource, gnomevfssrc will send special icecast http - * headers to the server to request additional icecast metainformation. If - * the server is not an icecast server, it will display the same behaviour - * as if the element-gnomevfssrc::iradio-mode property was not set. However, - * if the server is in fact an icecast server, gnomevfssrc will output - * data with a media type of application/x-icy, in which case you will - * need to use the #ICYDemux element as follow-up element to extract - * the icecast meta data and to determine the underlying media type. - * - * - * Example pipeline: - * - * gst-launch -v gnomevfssrc location=file:///home/joe/foo.xyz ! fakesink - * - * The above pipeline will simply read a local file and do nothing with the - * data read. Instead of gnomevfssrc, we could just as well have used the - * filesrc element here. - * - * - * Another example pipeline: - * - * gst-launch -v gnomevfssrc location=smb://othercomputer/foo.xyz ! filesink location=/home/joe/foo.xyz - * - * The above pipeline will copy a file from a remote host to the local file - * system using the Samba protocol. - * - * - * Yet another example pipeline: - * - * gst-launch -v gnomevfssrc location=http://music.foobar.com/demo.mp3 ! mad ! audioconvert ! audioresample ! alsasink - * - * The above pipeline will read and decode and play an mp3 file from a - * web server using the http protocol. - * - * - * - */ - - -#define BROKEN_SIG 1 -/*#undef BROKEN_SIG */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gst/gst-i18n-plugin.h" - -#include "gstgnomevfssrc.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* gnome-vfs.h doesn't include the following header, which we need: */ -#include - -GST_DEBUG_CATEGORY_STATIC (gnomevfssrc_debug); -#define GST_CAT_DEFAULT gnomevfssrc_debug - -static const GstElementDetails gst_gnome_vfs_src_details = -GST_ELEMENT_DETAILS ("GnomeVFS Source", - "Source/File", - "Read from any GnomeVFS-supported file", - "Bastien Nocera \n" - "Ronald S. Bultje "); - -static GStaticMutex count_lock = G_STATIC_MUTEX_INIT; -static gint ref_count = 0; -static gboolean vfs_owner = FALSE; - -static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -enum -{ - ARG_0, - ARG_HANDLE, - ARG_LOCATION, - ARG_IRADIO_MODE, - ARG_IRADIO_NAME, - ARG_IRADIO_GENRE, - ARG_IRADIO_URL, - ARG_IRADIO_TITLE -}; - -static void gst_gnome_vfs_src_base_init (gpointer g_class); -static void gst_gnome_vfs_src_class_init (GstGnomeVFSSrcClass * klass); -static void gst_gnome_vfs_src_init (GstGnomeVFSSrc * gnomevfssrc); -static void gst_gnome_vfs_src_finalize (GObject * object); -static void gst_gnome_vfs_src_uri_handler_init (gpointer g_iface, - gpointer iface_data); - -static void gst_gnome_vfs_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_gnome_vfs_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static gboolean gst_gnome_vfs_src_stop (GstBaseSrc * src); -static gboolean gst_gnome_vfs_src_start (GstBaseSrc * src); -static gboolean gst_gnome_vfs_src_is_seekable (GstBaseSrc * src); -static gboolean gst_gnome_vfs_src_check_get_range (GstBaseSrc * src); -static gboolean gst_gnome_vfs_src_get_size (GstBaseSrc * src, guint64 * size); -static GstFlowReturn gst_gnome_vfs_src_create (GstBaseSrc * basesrc, - guint64 offset, guint size, GstBuffer ** buffer); - -static GstElementClass *parent_class = NULL; - -GType -gst_gnome_vfs_src_get_type (void) -{ - static GType gnomevfssrc_type = 0; - - if (!gnomevfssrc_type) { - static const GTypeInfo gnomevfssrc_info = { - sizeof (GstGnomeVFSSrcClass), - gst_gnome_vfs_src_base_init, - NULL, - (GClassInitFunc) gst_gnome_vfs_src_class_init, - NULL, - NULL, - sizeof (GstGnomeVFSSrc), - 0, - (GInstanceInitFunc) gst_gnome_vfs_src_init, - }; - static const GInterfaceInfo urihandler_info = { - gst_gnome_vfs_src_uri_handler_init, - NULL, - NULL - }; - - gnomevfssrc_type = - g_type_register_static (GST_TYPE_BASE_SRC, - "GstGnomeVFSSrc", &gnomevfssrc_info, 0); - g_type_add_interface_static (gnomevfssrc_type, GST_TYPE_URI_HANDLER, - &urihandler_info); - } - return gnomevfssrc_type; -} - -static void -gst_gnome_vfs_src_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&srctemplate)); - gst_element_class_set_details (element_class, &gst_gnome_vfs_src_details); - - GST_DEBUG_CATEGORY_INIT (gnomevfssrc_debug, "gnomevfssrc", 0, - "Gnome-VFS Source"); -} - -static void -gst_gnome_vfs_src_class_init (GstGnomeVFSSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSrcClass *gstbasesrc_class; - - gobject_class = G_OBJECT_CLASS (klass); - gstelement_class = GST_ELEMENT_CLASS (klass); - gstbasesrc_class = GST_BASE_SRC_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = gst_gnome_vfs_src_finalize; - gobject_class->set_property = gst_gnome_vfs_src_set_property; - gobject_class->get_property = gst_gnome_vfs_src_get_property; - - /* properties */ - gst_element_class_install_std_props (GST_ELEMENT_CLASS (klass), - "location", ARG_LOCATION, G_PARAM_READWRITE, NULL); - g_object_class_install_property (gobject_class, - ARG_HANDLE, - g_param_spec_boxed ("handle", - "GnomeVFSHandle", "Handle for GnomeVFS", - GST_TYPE_GNOME_VFS_HANDLE, G_PARAM_READWRITE)); - - /* icecast stuff */ - g_object_class_install_property (gobject_class, - ARG_IRADIO_MODE, - g_param_spec_boolean ("iradio-mode", - "iradio-mode", - "Enable internet radio mode (extraction of shoutcast/icecast metadata)", - FALSE, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, - ARG_IRADIO_NAME, - g_param_spec_string ("iradio-name", - "iradio-name", "Name of the stream", NULL, G_PARAM_READABLE)); - g_object_class_install_property (gobject_class, - ARG_IRADIO_GENRE, - g_param_spec_string ("iradio-genre", - "iradio-genre", "Genre of the stream", NULL, G_PARAM_READABLE)); - g_object_class_install_property (gobject_class, - ARG_IRADIO_URL, - g_param_spec_string ("iradio-url", - "iradio-url", - "Homepage URL for radio stream", NULL, G_PARAM_READABLE)); - g_object_class_install_property (gobject_class, - ARG_IRADIO_TITLE, - g_param_spec_string ("iradio-title", - "iradio-title", - "Name of currently playing song", NULL, G_PARAM_READABLE)); - - gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_start); - gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_stop); - gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_get_size); - gstbasesrc_class->is_seekable = - GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_is_seekable); - gstbasesrc_class->check_get_range = - GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_check_get_range); - gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_create); -} - -static void -gst_gnome_vfs_src_init (GstGnomeVFSSrc * gnomevfssrc) -{ - gnomevfssrc->uri = NULL; - gnomevfssrc->uri_name = NULL; - gnomevfssrc->handle = NULL; - gnomevfssrc->curoffset = 0; - gnomevfssrc->seekable = FALSE; - - gnomevfssrc->icy_caps = NULL; - gnomevfssrc->iradio_mode = FALSE; - gnomevfssrc->http_callbacks_pushed = FALSE; - gnomevfssrc->iradio_name = NULL; - gnomevfssrc->iradio_genre = NULL; - gnomevfssrc->iradio_url = NULL; - gnomevfssrc->iradio_title = NULL; - - g_static_mutex_lock (&count_lock); - if (ref_count == 0) { - /* gnome vfs engine init */ - if (gnome_vfs_initialized () == FALSE) { - gnome_vfs_init (); - vfs_owner = TRUE; - } - } - ref_count++; - g_static_mutex_unlock (&count_lock); -} - -static void -gst_gnome_vfs_src_finalize (GObject * object) -{ - GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (object); - - g_static_mutex_lock (&count_lock); - ref_count--; - if (ref_count == 0 && vfs_owner) { - if (gnome_vfs_initialized () == TRUE) { - gnome_vfs_shutdown (); - } - } - g_static_mutex_unlock (&count_lock); - - if (src->uri) { - gnome_vfs_uri_unref (src->uri); - src->uri = NULL; - } - - g_free (src->uri_name); - src->uri_name = NULL; - - g_free (src->iradio_name); - src->iradio_name = NULL; - - g_free (src->iradio_genre); - src->iradio_genre = NULL; - - g_free (src->iradio_url); - src->iradio_url = NULL; - - g_free (src->iradio_title); - src->iradio_title = NULL; - - if (src->icy_caps) { - gst_caps_unref (src->icy_caps); - src->icy_caps = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -/* - * URI interface support. - */ - -static GstURIType -gst_gnome_vfs_src_uri_get_type (void) -{ - return GST_URI_SRC; -} - -static gchar ** -gst_gnome_vfs_src_uri_get_protocols (void) -{ - static gchar **protocols = NULL; - - if (!protocols) - protocols = gst_gnomevfs_get_supported_uris (); - - return protocols; -} - -static const gchar * -gst_gnome_vfs_src_uri_get_uri (GstURIHandler * handler) -{ - GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (handler); - - return src->uri_name; -} - -static gboolean -gst_gnome_vfs_src_uri_set_uri (GstURIHandler * handler, const gchar * uri) -{ - GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (handler); - - if (GST_STATE (src) == GST_STATE_PLAYING || - GST_STATE (src) == GST_STATE_PAUSED) - return FALSE; - - g_object_set (G_OBJECT (src), "location", uri, NULL); - - return TRUE; -} - -static void -gst_gnome_vfs_src_uri_handler_init (gpointer g_iface, gpointer iface_data) -{ - GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; - - iface->get_type = gst_gnome_vfs_src_uri_get_type; - iface->get_protocols = gst_gnome_vfs_src_uri_get_protocols; - iface->get_uri = gst_gnome_vfs_src_uri_get_uri; - iface->set_uri = gst_gnome_vfs_src_uri_set_uri; -} - -static void -gst_gnome_vfs_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstGnomeVFSSrc *src; - - src = GST_GNOME_VFS_SRC (object); - - switch (prop_id) { - case ARG_LOCATION:{ - const gchar *new_location; - - /* the element must be stopped or paused in order to do this */ - if (GST_STATE (src) == GST_STATE_PLAYING || - GST_STATE (src) == GST_STATE_PAUSED) - break; - - if (src->uri) { - gnome_vfs_uri_unref (src->uri); - src->uri = NULL; - } - if (src->uri_name) { - g_free (src->uri_name); - src->uri_name = NULL; - } - - new_location = g_value_get_string (value); - if (new_location) { - src->uri_name = gst_gnome_vfs_location_to_uri_string (new_location); - src->uri = gnome_vfs_uri_new (src->uri_name); - } - break; - } - case ARG_HANDLE: - if (GST_STATE (src) == GST_STATE_NULL || - GST_STATE (src) == GST_STATE_READY) { - if (src->uri) { - gnome_vfs_uri_unref (src->uri); - src->uri = NULL; - } - if (src->uri_name) { - g_free (src->uri_name); - src->uri_name = NULL; - } - src->handle = g_value_get_boxed (value); - } - break; - case ARG_IRADIO_MODE: - src->iradio_mode = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_gnome_vfs_src_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstGnomeVFSSrc *src; - - src = GST_GNOME_VFS_SRC (object); - - switch (prop_id) { - case ARG_LOCATION: - g_value_set_string (value, src->uri_name); - break; - case ARG_HANDLE: - g_value_set_boxed (value, src->handle); - break; - case ARG_IRADIO_MODE: - g_value_set_boolean (value, src->iradio_mode); - break; - case ARG_IRADIO_NAME: - g_value_set_string (value, src->iradio_name); - break; - case ARG_IRADIO_GENRE: - g_value_set_string (value, src->iradio_genre); - break; - case ARG_IRADIO_URL: - g_value_set_string (value, src->iradio_url); - break; - case ARG_IRADIO_TITLE: - g_value_set_string (value, src->iradio_title); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static char * -gst_gnome_vfs_src_unicodify (const char *str) -{ - const gchar *env_vars[] = { "GST_ICY_TAG_ENCODING", - "GST_TAG_ENCODING", NULL - }; - - return gst_tag_freeform_string_to_utf8 (str, -1, env_vars); -} - -static void -gst_gnome_vfs_src_send_additional_headers_callback (gconstpointer in, - gsize in_size, gpointer out, gsize out_size, gpointer callback_data) -{ - GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (callback_data); - GnomeVFSModuleCallbackAdditionalHeadersOut *out_args = - (GnomeVFSModuleCallbackAdditionalHeadersOut *) out; - - if (!src->iradio_mode) - return; - GST_DEBUG_OBJECT (src, "sending headers\n"); - - out_args->headers = g_list_append (out_args->headers, - g_strdup ("icy-metadata:1\r\n")); -} - -static void -gst_gnome_vfs_src_received_headers_callback (gconstpointer in, - gsize in_size, gpointer out, gsize out_size, gpointer callback_data) -{ - GList *i; - gint icy_metaint; - GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (callback_data); - GnomeVFSModuleCallbackReceivedHeadersIn *in_args = - (GnomeVFSModuleCallbackReceivedHeadersIn *) in; - - /* This is only used for internet radio stuff right now */ - if (!src->iradio_mode) - return; - - for (i = in_args->headers; i; i = i->next) { - char *data = (char *) i->data; - char *key = data; - char *value = strchr (data, ':'); - - if (!value) - continue; - - value++; - g_strstrip (value); - if (!strlen (value)) - continue; - - /* Icecast stuff */ - if (strncmp (data, "icy-metaint:", 12) == 0) { /* ugh */ - if (sscanf (data + 12, "%d", &icy_metaint) == 1) { - if (icy_metaint > 0) - src->icy_caps = gst_caps_new_simple ("application/x-icy", - "metadata-interval", G_TYPE_INT, icy_metaint, NULL); - } - continue; - } - - if (!strncmp (data, "icy-", 4)) - key = data + 4; - else - continue; - - GST_DEBUG_OBJECT (src, "key: %s", key); - if (!strncmp (key, "name", 4)) { - g_free (src->iradio_name); - src->iradio_name = gst_gnome_vfs_src_unicodify (value); - if (src->iradio_name) - g_object_notify (G_OBJECT (src), "iradio-name"); - } else if (!strncmp (key, "genre", 5)) { - g_free (src->iradio_genre); - src->iradio_genre = gst_gnome_vfs_src_unicodify (value); - if (src->iradio_genre) - g_object_notify (G_OBJECT (src), "iradio-genre"); - } else if (!strncmp (key, "url", 3)) { - g_free (src->iradio_url); - src->iradio_url = gst_gnome_vfs_src_unicodify (value); - if (src->iradio_url) - g_object_notify (G_OBJECT (src), "iradio-url"); - } - } -} - -static void -gst_gnome_vfs_src_push_callbacks (GstGnomeVFSSrc * src) -{ - if (src->http_callbacks_pushed) - return; - - GST_DEBUG_OBJECT (src, "pushing callbacks"); - gnome_vfs_module_callback_push - (GNOME_VFS_MODULE_CALLBACK_HTTP_SEND_ADDITIONAL_HEADERS, - gst_gnome_vfs_src_send_additional_headers_callback, src, NULL); - gnome_vfs_module_callback_push - (GNOME_VFS_MODULE_CALLBACK_HTTP_RECEIVED_HEADERS, - gst_gnome_vfs_src_received_headers_callback, src, NULL); - - src->http_callbacks_pushed = TRUE; -} - -static void -gst_gnome_vfs_src_pop_callbacks (GstGnomeVFSSrc * src) -{ - if (!src->http_callbacks_pushed) - return; - - GST_DEBUG_OBJECT (src, "popping callbacks"); - gnome_vfs_module_callback_pop - (GNOME_VFS_MODULE_CALLBACK_HTTP_SEND_ADDITIONAL_HEADERS); - gnome_vfs_module_callback_pop - (GNOME_VFS_MODULE_CALLBACK_HTTP_RECEIVED_HEADERS); - - src->http_callbacks_pushed = FALSE; -} - -/* - * Read a new buffer from src->reqoffset, takes care of events - * and seeking and such. - */ -static GstFlowReturn -gst_gnome_vfs_src_create (GstBaseSrc * basesrc, guint64 offset, guint size, - GstBuffer ** buffer) -{ - GnomeVFSResult res; - GstBuffer *buf; - GnomeVFSFileSize readbytes; - guint8 *data; - GstGnomeVFSSrc *src; - - src = GST_GNOME_VFS_SRC (basesrc); - - GST_DEBUG ("now at %llu, reading from %lld, size %u", src->curoffset, offset, - size); - - /* seek if required */ - if (G_UNLIKELY (src->curoffset != offset)) { - GST_DEBUG ("need to seek"); - if (src->seekable) { - GST_DEBUG ("seeking to %lld", offset); - res = gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_START, offset); - if (res != GNOME_VFS_OK) - goto seek_failed; - src->curoffset = offset; - } else { - goto cannot_seek; - } - } - - buf = gst_buffer_new_and_alloc (size); - - if (src->icy_caps) - gst_buffer_set_caps (buf, src->icy_caps); - - data = GST_BUFFER_DATA (buf); - GST_BUFFER_OFFSET (buf) = src->curoffset; - - res = gnome_vfs_read (src->handle, data, size, &readbytes); - - if (G_UNLIKELY (res == GNOME_VFS_ERROR_EOF || (res == GNOME_VFS_OK - && readbytes == 0))) - goto eos; - - GST_BUFFER_SIZE (buf) = readbytes; - - if (G_UNLIKELY (res != GNOME_VFS_OK)) - goto read_failed; - - src->curoffset += readbytes; - - /* we're done, return the buffer */ - *buffer = buf; - - return GST_FLOW_OK; - -seek_failed: - { - GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL), - ("Failed to seek to requested position %" G_GINT64_FORMAT ": %s", - offset, gnome_vfs_result_to_string (res))); - return GST_FLOW_ERROR; - } -cannot_seek: - { - GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL), - ("Requested seek from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT - " on non-seekable stream", src->curoffset, offset)); - return GST_FLOW_ERROR; - } -read_failed: - { - gst_buffer_unref (buf); - GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), - ("Failed to read data: %s", gnome_vfs_result_to_string (res))); - return GST_FLOW_ERROR; - } -eos: - { - gst_buffer_unref (buf); - GST_DEBUG_OBJECT (src, "Reading data gave EOS"); - return GST_FLOW_UNEXPECTED; - } -} - -static gboolean -gst_gnome_vfs_src_is_seekable (GstBaseSrc * basesrc) -{ - GstGnomeVFSSrc *src; - - src = GST_GNOME_VFS_SRC (basesrc); - - return src->seekable; -} - -static gboolean -gst_gnome_vfs_src_check_get_range (GstBaseSrc * basesrc) -{ - GstGnomeVFSSrc *src; - const gchar *protocol; - - src = GST_GNOME_VFS_SRC (basesrc); - - if (src->uri == NULL) { - GST_WARNING_OBJECT (src, "no URI set yet"); - return FALSE; - } - - if (gnome_vfs_uri_is_local (src->uri)) { - GST_LOG_OBJECT (src, "local URI (%s), assuming random access is possible", - GST_STR_NULL (src->uri_name)); - return TRUE; - } - - /* blacklist certain protocols we know won't work getrange-based */ - protocol = gnome_vfs_uri_get_scheme (src->uri); - if (protocol == NULL) - goto undecided; - - if (strcmp (protocol, "http") == 0 || strcmp (protocol, "https") == 0) { - GST_LOG_OBJECT (src, "blacklisted protocol '%s', no random access possible" - " (URI=%s)", protocol, GST_STR_NULL (src->uri_name)); - return FALSE; - } - - /* fall through to undecided */ - -undecided: - { - /* don't know what to do, let the basesrc class decide for us */ - GST_LOG_OBJECT (src, "undecided about URI '%s', let base class handle it", - GST_STR_NULL (src->uri_name)); - - if (GST_BASE_SRC_CLASS (parent_class)->check_get_range) - return GST_BASE_SRC_CLASS (parent_class)->check_get_range (basesrc); - - return FALSE; - } -} - -static gboolean -gst_gnome_vfs_src_get_size (GstBaseSrc * basesrc, guint64 * size) -{ - GstGnomeVFSSrc *src; - GnomeVFSFileInfo *info; - GnomeVFSFileInfoOptions options; - GnomeVFSResult res; - - src = GST_GNOME_VFS_SRC (basesrc); - - *size = -1; - info = gnome_vfs_file_info_new (); - options = GNOME_VFS_FILE_INFO_DEFAULT | GNOME_VFS_FILE_INFO_FOLLOW_LINKS; - res = gnome_vfs_get_file_info_from_handle (src->handle, info, options); - if (res == GNOME_VFS_OK) { - if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) != 0) { - *size = info->size; - GST_DEBUG_OBJECT (src, "from handle: %" G_GUINT64_FORMAT " bytes", *size); - } else if (src->own_handle && gnome_vfs_uri_is_local (src->uri)) { - GST_DEBUG_OBJECT (src, - "file size not known, file local, trying fallback"); - res = gnome_vfs_get_file_info_uri (src->uri, info, options); - if (res == GNOME_VFS_OK && - (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) != 0) { - *size = info->size; - GST_DEBUG_OBJECT (src, "from uri: %" G_GUINT64_FORMAT " bytes", *size); - } - } - } else { - GST_WARNING_OBJECT (src, "getting info failed: %s", - gnome_vfs_result_to_string (res)); - } - gnome_vfs_file_info_unref (info); - - if (*size == (GnomeVFSFileSize) - 1) - return FALSE; - - GST_DEBUG_OBJECT (src, "return size %" G_GUINT64_FORMAT, *size); - - return TRUE; -} - -/* open the file, do stuff necessary to go to PAUSED state */ -static gboolean -gst_gnome_vfs_src_start (GstBaseSrc * basesrc) -{ - GnomeVFSResult res; - GstGnomeVFSSrc *src; - - src = GST_GNOME_VFS_SRC (basesrc); - - gst_gnome_vfs_src_push_callbacks (src); - - if (src->uri != NULL) { - GnomeVFSOpenMode mode = GNOME_VFS_OPEN_READ; - - /* this can block... */ - res = gnome_vfs_open_uri (&src->handle, src->uri, mode); - if (res != GNOME_VFS_OK) - goto open_failed; - src->own_handle = TRUE; - } else if (!src->handle) { - goto no_filename; - } else { - src->own_handle = FALSE; - } - - if (gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_CURRENT, 0) == GNOME_VFS_OK) { - src->seekable = TRUE; - } else { - src->seekable = FALSE; - } - - return TRUE; - - /* ERRORS */ -open_failed: - { - gchar *filename = gnome_vfs_uri_to_string (src->uri, - GNOME_VFS_URI_HIDE_PASSWORD); - - gst_gnome_vfs_src_pop_callbacks (src); - - if (res == GNOME_VFS_ERROR_NOT_FOUND || - res == GNOME_VFS_ERROR_HOST_NOT_FOUND || - res == GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE) { - GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), - ("Could not open vfs file \"%s\" for reading: %s (%d)", - filename, gnome_vfs_result_to_string (res), res)); - } else { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), - ("Could not open vfs file \"%s\" for reading: %s (%d)", - filename, gnome_vfs_result_to_string (res), res)); - } - g_free (filename); - return FALSE; - } -no_filename: - { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("No filename given")); - return FALSE; - } -} - -static gboolean -gst_gnome_vfs_src_stop (GstBaseSrc * basesrc) -{ - GstGnomeVFSSrc *src; - - src = GST_GNOME_VFS_SRC (basesrc); - - gst_gnome_vfs_src_pop_callbacks (src); - - if (src->own_handle) { - GnomeVFSResult res; - - res = gnome_vfs_close (src->handle); - if (res != GNOME_VFS_OK) { - GST_ELEMENT_ERROR (src, RESOURCE, CLOSE, (NULL), - ("Could not close vfs handle: %s", gnome_vfs_result_to_string (res))); - } - src->handle = NULL; - } - src->curoffset = 0; - - if (src->icy_caps) { - gst_caps_unref (src->icy_caps); - src->icy_caps = NULL; - } - - return TRUE; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gnomevfs/gstgnomevfssrc.h --- a/gst_plugins_base/ext/gnomevfs/gstgnomevfssrc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * 2001 Bastien Nocera - * 2002 Kristian Rietveld - * 2002,2003 Colin Walters - * - * 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. - */ - -#ifndef __GST_GNOME_VFS_SRC_H__ -#define __GST_GNOME_VFS_SRC_H__ - -#include - -#include "gstgnomevfs.h" -#include "gstgnomevfsuri.h" -#include - -G_BEGIN_DECLS - -#define GST_TYPE_GNOME_VFS_SRC \ - (gst_gnome_vfs_src_get_type()) -#define GST_GNOME_VFS_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GNOME_VFS_SRC,GstGnomeVFSSrc)) -#define GST_GNOME_VFS_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GNOME_VFS_SRC,GstGnomeVFSSrcClass)) -#define GST_IS_GNOME_VFS_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GNOME_VFS_SRC)) -#define GST_IS_GNOME_VFS_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GNOME_VFS_SRC)) - -typedef struct _GstGnomeVFSSrc GstGnomeVFSSrc; -typedef struct _GstGnomeVFSSrcClass GstGnomeVFSSrcClass; - -/** - * GstGnomeVFSSrc: - * - * Opaque data structure. - */ -struct _GstGnomeVFSSrc -{ - GstBaseSrc basesrc; - - /* uri, file, ... */ - GnomeVFSURI *uri; - gchar *uri_name; - GnomeVFSHandle *handle; - gboolean own_handle; - GnomeVFSFileOffset curoffset; /* current offset in file */ - gboolean seekable; - - /* shoutcast/icecast metadata extraction handling */ - gboolean iradio_mode; - gboolean http_callbacks_pushed; - - GstCaps *icy_caps; - - gchar *iradio_name; - gchar *iradio_genre; - gchar *iradio_url; - gchar *iradio_title; -}; - -struct _GstGnomeVFSSrcClass -{ - GstBaseSrcClass basesrc_class; -}; - -GType gst_gnome_vfs_src_get_type (void); - -G_END_DECLS - -#endif /* __GST_GNOME_VFS_SRC_H__ */ - - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gnomevfs/gstgnomevfsuri.c --- a/gst_plugins_base/ext/gnomevfs/gstgnomevfsuri.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * 2001 Bastien Nocera - * 2003 Colin Walters - * - * gstgnomevfssink.c: - * - * 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. - */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include "gstgnomevfsuri.h" - -#include - -gchar ** -gst_gnomevfs_get_supported_uris (void) -{ - /* no dav/davs in the list, because they don't appear to be reliable enough */ - const gchar *uris[] = { - "http://localhost/bla", - "https://localhost/bla", - "file:///bla", - "smb://localhost/bla", - "ftp://localhost/bla", - "sftp://localhost/bla", - "nfs://localhost/bla", - "ssh://localhost/bla", - "burn://" - }; - GnomeVFSURI *uri; - gchar **result; - gint n, r = 0; - - result = g_new0 (gchar *, G_N_ELEMENTS (uris) + 1); - for (n = 0; n < G_N_ELEMENTS (uris); n++) { - uri = gnome_vfs_uri_new (uris[n]); - if (uri != NULL) { - gchar *protocol = g_strdup (uris[n]); - gint n; - - gnome_vfs_uri_unref (uri); - for (n = 0; protocol[n] != '\0'; n++) { - if (protocol[n] == ':') { - protocol[n] = '\0'; - break; - } - } - - GST_DEBUG ("adding protocol '%s'", protocol); - result[r++] = protocol; - } else { - GST_DEBUG ("could not create GnomeVfsUri from '%s'", uris[n]); - } - } - result[r] = NULL; - - return result; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/gnomevfs/gstgnomevfsuri.h --- a/gst_plugins_base/ext/gnomevfs/gstgnomevfsuri.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* GStreamer - * Copyright (C) 2003 Benjamin Otte - * - * 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. - */ - - -#ifndef __GST_GNOME_VFS_URI_H__ -#define __GST_GNOME_VFS_URI_H__ - -#include - -G_BEGIN_DECLS - -gchar **gst_gnomevfs_get_supported_uris (void); - -G_END_DECLS - -#endif /* __GST_GNOME_VFS_URI_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/libvisual/visual.c --- a/gst_plugins_base/ext/libvisual/visual.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,957 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Benjamin Otte - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#define GST_TYPE_VISUAL (gst_visual_get_type()) -#define GST_IS_VISUAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VISUAL)) -#define GST_VISUAL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VISUAL,GstVisual)) -#define GST_IS_VISUAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VISUAL)) -#define GST_VISUAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VISUAL,GstVisualClass)) -#define GST_VISUAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VISUAL, GstVisualClass)) - -typedef struct _GstVisual GstVisual; -typedef struct _GstVisualClass GstVisualClass; - -GST_DEBUG_CATEGORY_STATIC (libvisual_debug); -#define GST_CAT_DEFAULT (libvisual_debug) - -struct _GstVisual -{ - GstElement element; - - /* pads */ - GstPad *sinkpad; - GstPad *srcpad; - GstClockTime next_ts; - GstSegment segment; - - /* libvisual stuff */ - VisAudio *audio; - VisVideo *video; - VisActor *actor; - - /* audio/video state */ - gint channels; - gint rate; /* Input samplerate */ - gint bps; - - /* framerate numerator & denominator */ - gint fps_n; - gint fps_d; - gint width; - gint height; - GstClockTime duration; - guint outsize; - - /* samples per frame based on caps */ - guint spf; - - /* state stuff */ - GstAdapter *adapter; - guint count; - - /* QoS stuff *//* with LOCK */ - gdouble proportion; - GstClockTime earliest_time; -}; - -struct _GstVisualClass -{ - GstElementClass parent_class; - - VisPluginRef *plugin; -}; - -GType gst_visual_get_type (void); - - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN "; " -#if G_BYTE_ORDER == G_BIG_ENDIAN - GST_VIDEO_CAPS_RGB "; " -#else - GST_VIDEO_CAPS_BGR "; " -#endif - GST_VIDEO_CAPS_RGB_16) - ); - -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "width = (int) 16, " - "depth = (int) 16, " - "endianness = (int) BYTE_ORDER, " - "signed = (boolean) TRUE, " "channels = (int) { 1, 2 }, " -#if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000 - "rate = (int) { 8000, 11250, 22500, 32000, 44100, 48000, 96000 }" -#else - "rate = (int) [ 1000, MAX ]" -#endif - ) - ); - - -static void gst_visual_class_init (gpointer g_class, gpointer class_data); -static void gst_visual_init (GstVisual * visual); -static void gst_visual_dispose (GObject * object); - -static GstStateChangeReturn gst_visual_change_state (GstElement * element, - GstStateChange transition); -static GstFlowReturn gst_visual_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_visual_sink_event (GstPad * pad, GstEvent * event); -static gboolean gst_visual_src_event (GstPad * pad, GstEvent * event); - -static gboolean gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps); -static gboolean gst_visual_src_setcaps (GstPad * pad, GstCaps * caps); -static GstCaps *gst_visual_getcaps (GstPad * pad); -static void libvisual_log_handler (const char *message, const char *funcname, - void *priv); - -static GstElementClass *parent_class = NULL; - -GType -gst_visual_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - static const GTypeInfo info = { - sizeof (GstVisualClass), - NULL, - NULL, - gst_visual_class_init, - NULL, - NULL, - sizeof (GstVisual), - 0, - (GInstanceInitFunc) gst_visual_init, - }; - - type = g_type_register_static (GST_TYPE_ELEMENT, "GstVisual", &info, 0); - } - return type; -} - -static void -libvisual_log_handler (const char *message, const char *funcname, void *priv) -{ - GST_CAT_LEVEL_LOG (libvisual_debug, (GstDebugLevel) (priv), NULL, "%s - %s", - funcname, message); -} - -static void -gst_visual_class_init (gpointer g_class, gpointer class_data) -{ - GstVisualClass *klass = GST_VISUAL_CLASS (g_class); - GstElementClass *element = GST_ELEMENT_CLASS (g_class); - GObjectClass *object = G_OBJECT_CLASS (g_class); - - klass->plugin = class_data; - - element->change_state = gst_visual_change_state; - - if (class_data == NULL) { - parent_class = g_type_class_peek_parent (g_class); - } else { - GstElementDetails details = { - NULL, - "Visualization", - klass->plugin->info->about, - "Benjamin Otte " - }; - - details.longname = g_strdup_printf ("libvisual %s plugin v.%s", - klass->plugin->info->name, klass->plugin->info->version); - - /* FIXME: improve to only register what plugin supports? */ - gst_element_class_add_pad_template (element, - gst_static_pad_template_get (&src_template)); - gst_element_class_add_pad_template (element, - gst_static_pad_template_get (&sink_template)); - gst_element_class_set_details (element, &details); - g_free (details.longname); - } - - object->dispose = gst_visual_dispose; -} - -static void -gst_visual_init (GstVisual * visual) -{ - /* create the sink and src pads */ - visual->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); - gst_pad_set_setcaps_function (visual->sinkpad, gst_visual_sink_setcaps); - gst_pad_set_chain_function (visual->sinkpad, gst_visual_chain); - gst_pad_set_event_function (visual->sinkpad, gst_visual_sink_event); - gst_element_add_pad (GST_ELEMENT (visual), visual->sinkpad); - - visual->srcpad = gst_pad_new_from_static_template (&src_template, "src"); - gst_pad_set_setcaps_function (visual->srcpad, gst_visual_src_setcaps); - gst_pad_set_getcaps_function (visual->srcpad, gst_visual_getcaps); - gst_pad_set_event_function (visual->srcpad, gst_visual_src_event); - gst_element_add_pad (GST_ELEMENT (visual), visual->srcpad); - - visual->adapter = gst_adapter_new (); -} - -static void -gst_visual_clear_actors (GstVisual * visual) -{ - if (visual->actor) { - visual_object_unref (VISUAL_OBJECT (visual->actor)); - visual->actor = NULL; - } - if (visual->video) { - visual_object_unref (VISUAL_OBJECT (visual->video)); - visual->video = NULL; - } - if (visual->audio) { - visual_object_unref (VISUAL_OBJECT (visual->audio)); - visual->audio = NULL; - } -} - -static void -gst_visual_dispose (GObject * object) -{ - GstVisual *visual = GST_VISUAL (object); - - if (visual->adapter) { - g_object_unref (visual->adapter); - visual->adapter = NULL; - } - gst_visual_clear_actors (visual); - - GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); -} - -static void -gst_visual_reset (GstVisual * visual) -{ - visual->next_ts = -1; - gst_adapter_clear (visual->adapter); - gst_segment_init (&visual->segment, GST_FORMAT_UNDEFINED); - - GST_OBJECT_LOCK (visual); - visual->proportion = 1.0; - visual->earliest_time = -1; - GST_OBJECT_UNLOCK (visual); -} - -static GstCaps * -gst_visual_getcaps (GstPad * pad) -{ - GstCaps *ret; - GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad)); - int depths; - - if (!visual->actor) { - ret = gst_caps_copy (gst_pad_get_pad_template_caps (visual->srcpad)); - goto beach; - } - - ret = gst_caps_new_empty (); - depths = visual_actor_get_supported_depth (visual->actor); - if (depths < 0) { - /* FIXME: set an error */ - goto beach; - } - if (depths == VISUAL_VIDEO_DEPTH_GL) { - /* We can't handle GL only plugins */ - goto beach; - } - - GST_DEBUG_OBJECT (visual, "libvisual plugin supports depths %u (0x%04x)", - depths, depths); - /* if (depths & VISUAL_VIDEO_DEPTH_32BIT) Always supports 32bit output */ - gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN)); - - if (depths & VISUAL_VIDEO_DEPTH_24BIT) { -#if G_BYTE_ORDER == G_BIG_ENDIAN - gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_RGB)); -#else - gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_BGR)); -#endif - } - if (depths & VISUAL_VIDEO_DEPTH_16BIT) { - gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_RGB_16)); - } - -beach: - - GST_DEBUG_OBJECT (visual, "returning caps %" GST_PTR_FORMAT, ret); - gst_object_unref (visual); - return ret; -} - -static gboolean -gst_visual_src_setcaps (GstPad * pad, GstCaps * caps) -{ - GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad)); - GstStructure *structure; - gint depth, pitch; - - structure = gst_caps_get_structure (caps, 0); - - GST_DEBUG_OBJECT (visual, "src pad got caps %" GST_PTR_FORMAT, caps); - - if (!gst_structure_get_int (structure, "width", &visual->width)) - goto error; - if (!gst_structure_get_int (structure, "height", &visual->height)) - goto error; - if (!gst_structure_get_int (structure, "bpp", &depth)) - goto error; - if (!gst_structure_get_fraction (structure, "framerate", &visual->fps_n, - &visual->fps_d)) - goto error; - - visual_video_set_depth (visual->video, - visual_video_depth_enum_from_value (depth)); - visual_video_set_dimension (visual->video, visual->width, visual->height); - pitch = GST_ROUND_UP_4 (visual->width * visual->video->bpp); - visual_video_set_pitch (visual->video, pitch); - visual_actor_video_negotiate (visual->actor, 0, FALSE, FALSE); - - /* precalc some values */ - visual->outsize = visual->video->height * pitch; - visual->spf = - gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n); - visual->duration = - gst_util_uint64_scale_int (GST_SECOND, visual->fps_d, visual->fps_n); - - gst_object_unref (visual); - return TRUE; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (visual, "error parsing caps"); - gst_object_unref (visual); - return FALSE; - } -} - -static gboolean -gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps) -{ - GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad)); - GstStructure *structure; - - structure = gst_caps_get_structure (caps, 0); - - gst_structure_get_int (structure, "channels", &visual->channels); - gst_structure_get_int (structure, "rate", &visual->rate); - - /* this is how many samples we need to fill one frame at the requested - * framerate. */ - if (visual->fps_n != 0) { - visual->spf = - gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n); - } - visual->bps = visual->channels * sizeof (gint16); - - gst_object_unref (visual); - return TRUE; -} - -static gboolean -gst_vis_src_negotiate (GstVisual * visual) -{ - GstCaps *othercaps, *target, *intersect; - GstStructure *structure; - GstCaps *caps; - - caps = gst_pad_get_caps (visual->srcpad); - - /* see what the peer can do */ - othercaps = gst_pad_peer_get_caps (visual->srcpad); - if (othercaps) { - intersect = gst_caps_intersect (othercaps, caps); - gst_caps_unref (othercaps); - gst_caps_unref (caps); - - if (gst_caps_is_empty (intersect)) - goto no_format; - - target = gst_caps_copy_nth (intersect, 0); - gst_caps_unref (intersect); - } else { - /* need a copy, we'll be modifying it when fixating */ - target = gst_caps_copy (caps); - gst_caps_unref (caps); - } - - /* fixate in case something is not fixed. This does nothing if the value is - * already fixed. For video we always try to fixate to something like - * 320x240x30 by convention. */ - structure = gst_caps_get_structure (target, 0); - gst_structure_fixate_field_nearest_int (structure, "width", 320); - gst_structure_fixate_field_nearest_int (structure, "height", 240); - gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1); - - gst_pad_set_caps (visual->srcpad, target); - gst_caps_unref (target); - - return TRUE; - - /* ERRORS */ -no_format: - { - GST_ELEMENT_ERROR (visual, STREAM, FORMAT, (NULL), - ("could not negotiate output format")); - gst_caps_unref (intersect); - return FALSE; - } -} - -static gboolean -gst_visual_sink_event (GstPad * pad, GstEvent * event) -{ - GstVisual *visual; - gboolean res; - - visual = GST_VISUAL (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - res = gst_pad_push_event (visual->srcpad, event); - break; - case GST_EVENT_FLUSH_STOP: - /* reset QoS and adapter. */ - gst_visual_reset (visual); - res = gst_pad_push_event (visual->srcpad, event); - break; - case GST_EVENT_NEWSEGMENT: - { - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - gboolean update; - - /* the newsegment values are used to clip the input samples - * and to convert the incomming timestamps to running time so - * we can do QoS */ - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); - - /* now configure the values */ - gst_segment_set_newsegment_full (&visual->segment, update, - rate, arate, format, start, stop, time); - - /* and forward */ - res = gst_pad_push_event (visual->srcpad, event); - break; - } - default: - res = gst_pad_push_event (visual->srcpad, event); - break; - } - - gst_object_unref (visual); - return res; -} - -static gboolean -gst_visual_src_event (GstPad * pad, GstEvent * event) -{ - GstVisual *visual; - gboolean res; - - visual = GST_VISUAL (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_QOS: - { - gdouble proportion; - GstClockTimeDiff diff; - GstClockTime timestamp; - - gst_event_parse_qos (event, &proportion, &diff, ×tamp); - - /* save stuff for the _chain function */ - GST_OBJECT_LOCK (visual); - visual->proportion = proportion; - if (diff >= 0) - /* we're late, this is a good estimate for next displayable - * frame (see part-qos.txt) */ - visual->earliest_time = timestamp + 2 * diff + visual->duration; - else - visual->earliest_time = timestamp + diff; - - GST_OBJECT_UNLOCK (visual); - - res = gst_pad_push_event (visual->sinkpad, event); - break; - } - default: - res = gst_pad_push_event (visual->sinkpad, event); - break; - } - - gst_object_unref (visual); - return res; -} - -/* allocate and output buffer, if no format was negotiated, this - * function will negotiate one. After calling this function, a - * reverse negotiation could have happened. */ -static GstFlowReturn -get_buffer (GstVisual * visual, GstBuffer ** outbuf) -{ - GstFlowReturn ret; - - /* we don't know an output format yet, pick one */ - if (GST_PAD_CAPS (visual->srcpad) == NULL) { - if (!gst_vis_src_negotiate (visual)) - return GST_FLOW_NOT_NEGOTIATED; - } - - GST_DEBUG_OBJECT (visual, "allocating output buffer with caps %" - GST_PTR_FORMAT, GST_PAD_CAPS (visual->srcpad)); - - /* now allocate a buffer with the last negotiated format. - * Downstream could renegotiate a new format, which will trigger - * our setcaps function on the source pad. */ - ret = - gst_pad_alloc_buffer_and_set_caps (visual->srcpad, - GST_BUFFER_OFFSET_NONE, visual->outsize, - GST_PAD_CAPS (visual->srcpad), outbuf); - - /* no buffer allocated, we don't care why. */ - if (ret != GST_FLOW_OK) - return ret; - - return GST_FLOW_OK; -} - -static GstFlowReturn -gst_visual_chain (GstPad * pad, GstBuffer * buffer) -{ - GstBuffer *outbuf = NULL; - guint i; - GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad)); - GstFlowReturn ret = GST_FLOW_OK; - guint avail; - - GST_DEBUG_OBJECT (visual, "chain function called"); - - /* If we don't have an output format yet, preallocate a buffer to try and - * set one */ - if (GST_PAD_CAPS (visual->srcpad) == NULL) { - ret = get_buffer (visual, &outbuf); - if (ret != GST_FLOW_OK) { - gst_buffer_unref (buffer); - goto beach; - } - } - - /* resync on DISCONT */ - if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { - gst_adapter_clear (visual->adapter); - visual->next_ts = -1; - } - - /* Match timestamps from the incoming audio */ - if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE) - visual->next_ts = GST_BUFFER_TIMESTAMP (buffer); - - GST_DEBUG_OBJECT (visual, - "Input buffer has %d samples, time=%" G_GUINT64_FORMAT, - GST_BUFFER_SIZE (buffer) / visual->bps, GST_BUFFER_TIMESTAMP (buffer)); - - gst_adapter_push (visual->adapter, buffer); - - while (TRUE) { - gboolean need_skip; - const guint16 *data; - - GST_DEBUG_OBJECT (visual, "processing buffer"); - - avail = gst_adapter_available (visual->adapter); - GST_DEBUG_OBJECT (visual, "avail now %u", avail); - - /* we need at least 512 samples */ - if (avail < 512 * visual->bps) - break; - - /* we need at least enough samples to make one frame */ - if (avail < visual->spf * visual->bps) - break; - - if (visual->next_ts != -1) { - gint64 qostime; - - /* QoS is done on running time */ - qostime = gst_segment_to_running_time (&visual->segment, GST_FORMAT_TIME, - visual->next_ts); - - GST_OBJECT_LOCK (visual); - /* check for QoS, don't compute buffers that are known to be late */ - need_skip = visual->earliest_time != -1 && - qostime <= visual->earliest_time; - GST_OBJECT_UNLOCK (visual); - - if (need_skip) { - GST_WARNING_OBJECT (visual, - "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, - GST_TIME_ARGS (qostime), GST_TIME_ARGS (visual->earliest_time)); - goto skip; - } - } - - /* Read 512 samples per channel */ - data = - (const guint16 *) gst_adapter_peek (visual->adapter, 512 * visual->bps); - -#if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000 - { - VisBuffer *lbuf, *rbuf; - guint16 ldata[512], rdata[512]; - VisAudioSampleRateType rate; - - lbuf = visual_buffer_new_with_buffer (ldata, sizeof (ldata), NULL); - rbuf = visual_buffer_new_with_buffer (rdata, sizeof (rdata), NULL); - - if (visual->channels == 2) { - for (i = 0; i < 512; i++) { - ldata[i] = *data++; - rdata[i] = *data++; - } - } else { - for (i = 0; i < 512; i++) { - ldata[i] = *data; - rdata[i] = *data++; - } - } - - switch (visual->rate) { - case 8000: - rate = VISUAL_AUDIO_SAMPLE_RATE_8000; - break; - case 11250: - rate = VISUAL_AUDIO_SAMPLE_RATE_11250; - break; - case 22500: - rate = VISUAL_AUDIO_SAMPLE_RATE_22500; - break; - case 32000: - rate = VISUAL_AUDIO_SAMPLE_RATE_32000; - break; - case 44100: - rate = VISUAL_AUDIO_SAMPLE_RATE_44100; - break; - case 48000: - rate = VISUAL_AUDIO_SAMPLE_RATE_48000; - break; - case 96000: - rate = VISUAL_AUDIO_SAMPLE_RATE_96000; - break; - default: - visual_object_unref (VISUAL_OBJECT (lbuf)); - visual_object_unref (VISUAL_OBJECT (rbuf)); - GST_ERROR_OBJECT (visual, "unsupported rate %d", visual->rate); - ret = GST_FLOW_ERROR; - goto beach; - break; - } - - visual_audio_samplepool_input_channel (visual->audio->samplepool, - lbuf, - rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, VISUAL_AUDIO_CHANNEL_LEFT); - visual_audio_samplepool_input_channel (visual->audio->samplepool, - rbuf, - rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, VISUAL_AUDIO_CHANNEL_RIGHT); - - visual_object_unref (VISUAL_OBJECT (lbuf)); - visual_object_unref (VISUAL_OBJECT (rbuf)); - - } -#else - if (visual->channels == 2) { - for (i = 0; i < 512; i++) { - visual->audio->plugpcm[0][i] = *data++; - visual->audio->plugpcm[1][i] = *data++; - } - } else { - for (i = 0; i < 512; i++) { - visual->audio->plugpcm[0][i] = *data; - visual->audio->plugpcm[1][i] = *data++; - } - } -#endif - - /* alloc a buffer if we don't have one yet, this happens - * when we pushed a buffer in this while loop before */ - if (outbuf == NULL) { - ret = get_buffer (visual, &outbuf); - if (ret != GST_FLOW_OK) { - goto beach; - } - } - visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf)); - visual_audio_analyze (visual->audio); - visual_actor_run (visual->actor, visual->audio); - visual_video_set_buffer (visual->video, NULL); - GST_DEBUG_OBJECT (visual, "rendered one frame"); - - GST_BUFFER_TIMESTAMP (outbuf) = visual->next_ts; - GST_BUFFER_DURATION (outbuf) = visual->duration; - - ret = gst_pad_push (visual->srcpad, outbuf); - outbuf = NULL; - - skip: - /* interpollate next timestamp */ - if (visual->next_ts != -1) - visual->next_ts += visual->duration; - - GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input", - visual->spf); - - /* Flush out the number of samples per frame */ - gst_adapter_flush (visual->adapter, visual->spf * visual->bps); - - /* quit the loop if something was wrong */ - if (ret != GST_FLOW_OK) - break; - } - -beach: - - if (outbuf != NULL) - gst_buffer_unref (outbuf); - - gst_object_unref (visual); - - return ret; -} - -static GstStateChangeReturn -gst_visual_change_state (GstElement * element, GstStateChange transition) -{ - GstVisual *visual = GST_VISUAL (element); - GstStateChangeReturn ret; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - visual->actor = - visual_actor_new (GST_VISUAL_GET_CLASS (visual)->plugin->info-> - plugname); - visual->video = visual_video_new (); - visual->audio = visual_audio_new (); - /* can't have a play without actors */ - if (!visual->actor || !visual->video) - goto no_actors; - - if (visual_actor_realize (visual->actor) != 0) - goto no_realize; - - visual_actor_set_video (visual->actor, visual->video); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_visual_reset (visual); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_visual_clear_actors (visual); - break; - default: - break; - } - - return ret; - - /* ERRORS */ -no_actors: - { - GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL), - ("could not create actors")); - gst_visual_clear_actors (visual); - return GST_STATE_CHANGE_FAILURE; - } -no_realize: - { - GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL), - ("could not realize actor")); - gst_visual_clear_actors (visual); - return GST_STATE_CHANGE_FAILURE; - } -} - -static void -make_valid_name (char *name) -{ - /* - * Replace invalid chars with _ in the type name - */ - static const gchar extra_chars[] = "-_+"; - gchar *p = name; - - for (; *p; p++) { - int valid = ((p[0] >= 'A' && p[0] <= 'Z') || - (p[0] >= 'a' && p[0] <= 'z') || - (p[0] >= '0' && p[0] <= '9') || strchr (extra_chars, p[0])); - if (!valid) - *p = '_'; - } -} - -static gboolean -gst_visual_actor_plugin_is_gl (VisObject * plugin, const gchar * name) -{ - gboolean is_gl; - gint depth; - -#if !defined(VISUAL_API_VERSION) - - depth = VISUAL_PLUGIN_ACTOR (plugin)->depth; - is_gl = (depth == VISUAL_VIDEO_DEPTH_GL); - -#elif VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000 - - depth = VISUAL_ACTOR_PLUGIN (plugin)->vidoptions.depth; - /* FIXME: how to figure this out correctly in 0.4? */ - is_gl = (depth & VISUAL_VIDEO_DEPTH_GL) == VISUAL_VIDEO_DEPTH_GL; - -#else -# error what libvisual version is this? -#endif - - if (!is_gl) { - GST_DEBUG ("plugin %s is not a GL plugin (%d), registering", name, depth); - } else { - GST_DEBUG ("plugin %s is a GL plugin (%d), ignoring", name, depth); - } - - return is_gl; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - guint i, count; - VisList *list; - - GST_DEBUG_CATEGORY_INIT (libvisual_debug, "libvisual", 0, - "libvisual audio visualisations"); - - visual_log_set_verboseness (VISUAL_LOG_VERBOSENESS_LOW); - visual_log_set_info_handler (libvisual_log_handler, (void *) GST_LEVEL_INFO); - visual_log_set_warning_handler (libvisual_log_handler, - (void *) GST_LEVEL_WARNING); - visual_log_set_critical_handler (libvisual_log_handler, - (void *) GST_LEVEL_ERROR); - visual_log_set_error_handler (libvisual_log_handler, - (void *) GST_LEVEL_ERROR); - - if (!visual_is_initialized ()) - if (visual_init (NULL, NULL) != 0) - return FALSE; - - list = visual_actor_get_list (); - -#if !defined(VISUAL_API_VERSION) - count = visual_list_count (list); -#elif VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000 - count = visual_collection_size (VISUAL_COLLECTION (list)); -#endif - - for (i = 0; i < count; i++) { - VisPluginRef *ref = visual_list_get (list, i); - VisPluginData *visplugin = NULL; - gboolean skip = FALSE; - GType type; - gchar *name; - GTypeInfo info = { - sizeof (GstVisualClass), - NULL, - NULL, - gst_visual_class_init, - NULL, - ref, - sizeof (GstVisual), - 0, - NULL - }; - - visplugin = visual_plugin_load (ref); - - if (ref->info->plugname == NULL) - continue; - - /* Blacklist some plugins */ - if (strcmp (ref->info->plugname, "gstreamer") == 0 || - strcmp (ref->info->plugname, "gdkpixbuf") == 0) { - skip = TRUE; - } else { - /* Ignore plugins that only support GL output for now */ - skip = gst_visual_actor_plugin_is_gl (visplugin->info->plugin, - visplugin->info->plugname); - } - - visual_plugin_unload (visplugin); - - if (!skip) { - name = g_strdup_printf ("GstVisual%s", ref->info->plugname); - make_valid_name (name); - type = g_type_register_static (GST_TYPE_VISUAL, name, &info, 0); - g_free (name); - - name = g_strdup_printf ("libvisual_%s", ref->info->plugname); - make_valid_name (name); - if (!gst_element_register (plugin, name, GST_RANK_NONE, type)) { - g_free (name); - return FALSE; - } - g_free (name); - } - } - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "libvisual", - "libvisual visualization plugins", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/ogg/gstogg.c --- a/gst_plugins_base/ext/ogg/gstogg.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -extern gboolean gst_ogg_demux_plugin_init (GstPlugin * plugin); -extern gboolean gst_ogg_mux_plugin_init (GstPlugin * plugin); -extern gboolean gst_ogm_parse_plugin_init (GstPlugin * plugin); -extern gboolean gst_ogg_parse_plugin_init (GstPlugin * plugin); -extern gboolean gst_ogg_avi_parse_plugin_init (GstPlugin * plugin); - -static gboolean -plugin_init (GstPlugin * plugin) -{ - gst_ogg_demux_plugin_init (plugin); - gst_ogg_mux_plugin_init (plugin); - gst_ogm_parse_plugin_init (plugin); - gst_ogg_parse_plugin_init (plugin); - gst_ogg_avi_parse_plugin_init (plugin); - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "ogg", - "ogg stream manipulation (info about ogg: http://xiph.org)", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/ogg/gstoggaviparse.c --- a/gst_plugins_base/ext/ogg/gstoggaviparse.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,478 +0,0 @@ -/* GStreamer - * Copyright (C) 2006 Wim Taymans - * - * gstoggaviparse.c: ogg avi stream parser - * - * 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. - */ - -/* - * Ogg in AVI is mostly done for vorbis audio. In the codec_data we receive the - * first 3 packets of the raw vorbis data. On the sinkpad we receive full-blown Ogg - * pages. - * Before extracting the packets out of the ogg pages, we push the raw vorbis - * header packets to the decoder. - * We don't use the incomming timestamps but use the ganulepos on the ogg pages - * directly. - * This parser only does ogg/vorbis for now. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include - -static const GstElementDetails gst_ogg_avi_parse_details = -GST_ELEMENT_DETAILS ("Ogg AVI parser", - "Codec/Parser", - "parse an ogg avi stream into pages (info about ogg: http://xiph.org)", - "Wim Taymans "); - -GST_DEBUG_CATEGORY_STATIC (gst_ogg_avi_parse_debug); -#define GST_CAT_DEFAULT gst_ogg_avi_parse_debug - -#define GST_TYPE_OGG_AVI_PARSE (gst_ogg_avi_parse_get_type()) -#define GST_OGG_AVI_PARSE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_AVI_PARSE, GstOggAviParse)) -#define GST_OGG_AVI_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_AVI_PARSE, GstOggAviParse)) -#define GST_IS_OGG_AVI_PARSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_AVI_PARSE)) -#define GST_IS_OGG_AVI_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_AVI_PARSE)) - -static GType gst_ogg_avi_parse_get_type (void); - -typedef struct _GstOggAviParse GstOggAviParse; -typedef struct _GstOggAviParseClass GstOggAviParseClass; - -struct _GstOggAviParse -{ - GstElement element; - - GstPad *sinkpad; - GstPad *srcpad; - - gboolean discont; - gint serial; - - ogg_sync_state sync; - ogg_stream_state stream; -}; - -struct _GstOggAviParseClass -{ - GstElementClass parent_class; -}; - -static void gst_ogg_avi_parse_base_init (gpointer g_class); -static void gst_ogg_avi_parse_class_init (GstOggAviParseClass * klass); -static void gst_ogg_avi_parse_init (GstOggAviParse * ogg); -static GstElementClass *parent_class = NULL; - -static GType -gst_ogg_avi_parse_get_type (void) -{ - static GType ogg_avi_parse_type = 0; - - if (!ogg_avi_parse_type) { - static const GTypeInfo ogg_avi_parse_info = { - sizeof (GstOggAviParseClass), - gst_ogg_avi_parse_base_init, - NULL, - (GClassInitFunc) gst_ogg_avi_parse_class_init, - NULL, - NULL, - sizeof (GstOggAviParse), - 0, - (GInstanceInitFunc) gst_ogg_avi_parse_init, - }; - - ogg_avi_parse_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstOggAviParse", - &ogg_avi_parse_info, 0); - } - return ogg_avi_parse_type; -} - -enum -{ - PROP_0 -}; - -static GstStaticPadTemplate ogg_avi_parse_src_template_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-vorbis") - ); - -static GstStaticPadTemplate ogg_avi_parse_sink_template_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-ogg-avi") - ); - -static void gst_ogg_avi_parse_finalize (GObject * object); -static GstStateChangeReturn gst_ogg_avi_parse_change_state (GstElement * - element, GstStateChange transition); -static gboolean gst_ogg_avi_parse_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_ogg_avi_parse_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_ogg_avi_parse_setcaps (GstPad * pad, GstCaps * caps); - -static void -gst_ogg_avi_parse_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_ogg_avi_parse_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&ogg_avi_parse_sink_template_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&ogg_avi_parse_src_template_factory)); -} - -static void -gst_ogg_avi_parse_class_init (GstOggAviParseClass * klass) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gstelement_class->change_state = gst_ogg_avi_parse_change_state; - - gobject_class->finalize = gst_ogg_avi_parse_finalize; -} - -static void -gst_ogg_avi_parse_init (GstOggAviParse * ogg) -{ - /* create the sink and source pads */ - ogg->sinkpad = - gst_pad_new_from_static_template (&ogg_avi_parse_sink_template_factory, - "sink"); - gst_pad_set_setcaps_function (ogg->sinkpad, gst_ogg_avi_parse_setcaps); - gst_pad_set_event_function (ogg->sinkpad, gst_ogg_avi_parse_event); - gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_avi_parse_chain); - gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad); - - ogg->srcpad = - gst_pad_new_from_static_template (&ogg_avi_parse_src_template_factory, - "src"); - gst_pad_use_fixed_caps (ogg->srcpad); - gst_element_add_pad (GST_ELEMENT (ogg), ogg->srcpad); -} - -static void -gst_ogg_avi_parse_finalize (GObject * object) -{ - GstOggAviParse *ogg = GST_OGG_AVI_PARSE (object); - - GST_LOG_OBJECT (ogg, "Disposing of object %p", ogg); - - ogg_sync_clear (&ogg->sync); - ogg_stream_clear (&ogg->stream); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -gst_ogg_avi_parse_setcaps (GstPad * pad, GstCaps * caps) -{ - GstOggAviParse *ogg; - GstStructure *structure; - const GValue *codec_data; - GstBuffer *buffer; - guint8 *data; - guint size; - guint32 sizes[3]; - GstCaps *outcaps; - gint i, offs; - - ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad)); - - structure = gst_caps_get_structure (caps, 0); - - /* take codec data */ - codec_data = gst_structure_get_value (structure, "codec_data"); - if (codec_data == NULL) - goto no_data; - - /* only buffers are valid */ - if (G_VALUE_TYPE (codec_data) != GST_TYPE_BUFFER) - goto wrong_format; - - /* Now parse the data */ - buffer = gst_value_get_buffer (codec_data); - - /* first 22 bytes are bits_per_sample, channel_mask, GUID - * Then we get 3 LE guint32 with the 3 header sizes - * then we get the bytes of the 3 headers. */ - data = GST_BUFFER_DATA (buffer); - size = GST_BUFFER_SIZE (buffer); - - GST_LOG_OBJECT (ogg, "configuring codec_data of size %u", size); - - /* skip headers */ - data += 22; - size -= 22; - - /* we need at least 12 bytes for the packet sizes of the 3 headers */ - if (size < 12) - goto buffer_too_small; - - /* read sizes of the 3 headers */ - sizes[0] = GST_READ_UINT32_LE (data); - sizes[1] = GST_READ_UINT32_LE (data + 4); - sizes[2] = GST_READ_UINT32_LE (data + 8); - - GST_DEBUG_OBJECT (ogg, "header sizes: %u %u %u", sizes[0], sizes[1], - sizes[2]); - - data += 12; - size -= 12; - - /* and we need at least enough data for all the headers */ - if (size < sizes[0] + sizes[1] + sizes[2]) - goto buffer_too_small; - - /* set caps */ - outcaps = gst_caps_new_simple ("audio/x-vorbis", NULL); - gst_pad_set_caps (ogg->srcpad, outcaps); - - /* copy header data */ - offs = 34; - for (i = 0; i < 3; i++) { - GstBuffer *out; - - /* now output the raw vorbis header packets */ - out = gst_buffer_create_sub (buffer, offs, sizes[i]); - gst_buffer_set_caps (out, outcaps); - gst_pad_push (ogg->srcpad, out); - - offs += sizes[i]; - } - gst_caps_unref (outcaps); - - return TRUE; - - /* ERRORS */ -no_data: - { - GST_DEBUG_OBJECT (ogg, "no codec_data found in caps"); - return FALSE; - } -wrong_format: - { - GST_DEBUG_OBJECT (ogg, "codec_data is not a buffer"); - return FALSE; - } -buffer_too_small: - { - GST_DEBUG_OBJECT (ogg, "codec_data is too small"); - return FALSE; - } -} - -static gboolean -gst_ogg_avi_parse_event (GstPad * pad, GstEvent * event) -{ - GstOggAviParse *ogg; - gboolean ret; - - ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - ret = gst_pad_push_event (ogg->srcpad, event); - break; - case GST_EVENT_FLUSH_STOP: - ogg_sync_reset (&ogg->sync); - ogg_stream_reset (&ogg->stream); - ogg->discont = TRUE; - ret = gst_pad_push_event (ogg->srcpad, event); - break; - default: - ret = gst_pad_push_event (ogg->srcpad, event); - break; - } - return ret; -} - -static GstFlowReturn -gst_ogg_avi_parse_push_packet (GstOggAviParse * ogg, ogg_packet * packet) -{ - GstBuffer *buffer; - GstFlowReturn result; - - /* allocate space for header and body */ - buffer = gst_buffer_new_and_alloc (packet->bytes); - memcpy (GST_BUFFER_DATA (buffer), packet->packet, packet->bytes); - - GST_LOG_OBJECT (ogg, "created buffer %p from page", buffer); - - GST_BUFFER_OFFSET_END (buffer) = packet->granulepos; - - if (ogg->discont) { - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); - ogg->discont = FALSE; - } - - result = gst_pad_push (ogg->srcpad, buffer); - - return result; -} - -static GstFlowReturn -gst_ogg_avi_parse_chain (GstPad * pad, GstBuffer * buffer) -{ - GstFlowReturn result = GST_FLOW_OK; - GstOggAviParse *ogg; - guint8 *data; - guint size; - gchar *oggbuf; - gint ret = -1; - - ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad)); - - data = GST_BUFFER_DATA (buffer); - size = GST_BUFFER_SIZE (buffer); - - GST_LOG_OBJECT (ogg, "Chain function received buffer of size %d", size); - - if (GST_BUFFER_IS_DISCONT (buffer)) { - ogg_sync_reset (&ogg->sync); - ogg->discont = TRUE; - } - - /* write data to sync layer */ - oggbuf = ogg_sync_buffer (&ogg->sync, size); - memcpy (oggbuf, data, size); - ogg_sync_wrote (&ogg->sync, size); - gst_buffer_unref (buffer); - - /* try to get as many packets out of the stream as possible */ - do { - ogg_page page; - - /* try to swap out a page */ - ret = ogg_sync_pageout (&ogg->sync, &page); - if (ret == 0) { - GST_DEBUG_OBJECT (ogg, "need more data"); - break; - } else if (ret == -1) { - GST_DEBUG_OBJECT (ogg, "discont in pages"); - ogg->discont = TRUE; - } else { - /* new unknown stream, init the ogg stream with the serial number of the - * page. */ - if (ogg->serial == -1) { - ogg->serial = ogg_page_serialno (&page); - ogg_stream_init (&ogg->stream, ogg->serial); - } - - /* submit page */ - if (ogg_stream_pagein (&ogg->stream, &page) != 0) { - GST_WARNING_OBJECT (ogg, "ogg stream choked on page resetting stream"); - ogg_sync_reset (&ogg->sync); - ogg->discont = TRUE; - continue; - } - - /* try to get as many packets as possible out of the page */ - do { - ogg_packet packet; - - ret = ogg_stream_packetout (&ogg->stream, &packet); - GST_LOG_OBJECT (ogg, "packetout gave %d", ret); - switch (ret) { - case 0: - break; - case -1: - /* out of sync, We mark a DISCONT. */ - ogg->discont = TRUE; - break; - case 1: - result = gst_ogg_avi_parse_push_packet (ogg, &packet); - if (GST_FLOW_IS_FATAL (result)) - goto done; - break; - default: - GST_WARNING_OBJECT (ogg, - "invalid return value %d for ogg_stream_packetout, resetting stream", - ret); - break; - } - } - while (ret != 0); - } - } - while (ret != 0); - -done: - return result; -} - -static GstStateChangeReturn -gst_ogg_avi_parse_change_state (GstElement * element, GstStateChange transition) -{ - GstOggAviParse *ogg; - GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; - - ogg = GST_OGG_AVI_PARSE (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - ogg_sync_init (&ogg->sync); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - ogg_sync_reset (&ogg->sync); - ogg_stream_reset (&ogg->stream); - ogg->serial = -1; - ogg->discont = TRUE; - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - result = parent_class->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_NULL: - ogg_sync_clear (&ogg->sync); - break; - default: - break; - } - return result; -} - -gboolean -gst_ogg_avi_parse_plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (gst_ogg_avi_parse_debug, "oggaviparse", 0, - "ogg avi parser"); - - return gst_element_register (plugin, "oggaviparse", GST_RANK_PRIMARY, - GST_TYPE_OGG_AVI_PARSE); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/ogg/gstoggdemux.c --- a/gst_plugins_base/ext/ogg/gstoggdemux.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3323 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Wim Taymans - * - * gstoggdemux.c: ogg stream demuxer - * - * 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. - */ - -/** - * SECTION:element-oggdemux - * @short_description: a demuxer for ogg files - * - * - * - * This element demuxes ogg files into their encoded audio and video components. - * - * Example pipelines - * - * - * gst-launch -v filesrc location=test.ogg ! oggdemux ! vorbisdec ! audioconvert ! alsasink - * - * Decodes the vorbis audio stored inside an ogg container. - * - * - * - * Last reviewed on 2006-12-30 (0.10.5) - */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include - -#include "gstoggdemux.h" - -static const GstElementDetails gst_ogg_demux_details = -GST_ELEMENT_DETAILS ("Ogg demuxer", - "Codec/Demuxer", - "demux ogg streams (info about ogg: http://xiph.org)", - "Wim Taymans "); - -#define CHUNKSIZE (8500) /* this is out of vorbisfile */ -#define SKELETON_FISHEAD_SIZE 64 -#define SKELETON_FISBONE_MIN_SIZE 52 - -#define GST_FLOW_LIMIT GST_FLOW_CUSTOM_ERROR - -GST_DEBUG_CATEGORY_STATIC (gst_ogg_demux_debug); -GST_DEBUG_CATEGORY_STATIC (gst_ogg_demux_setup_debug); -#define GST_CAT_DEFAULT gst_ogg_demux_debug - -static ogg_page * -gst_ogg_page_copy (ogg_page * page) -{ - ogg_page *p = g_new0 (ogg_page, 1); - - /* make a copy of the page */ - p->header = g_memdup (page->header, page->header_len); - p->header_len = page->header_len; - p->body = g_memdup (page->body, page->body_len); - p->body_len = page->body_len; - - return p; -} - -static void -gst_ogg_page_free (ogg_page * page) -{ - g_free (page->header); - g_free (page->body); - g_free (page); -} - -static GstStaticPadTemplate internaltemplate = -GST_STATIC_PAD_TEMPLATE ("internal", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static gboolean gst_ogg_demux_collect_chain_info (GstOggDemux * ogg, - GstOggChain * chain); -static gboolean gst_ogg_demux_activate_chain (GstOggDemux * ogg, - GstOggChain * chain, GstEvent * event); -static void gst_ogg_chain_mark_discont (GstOggChain * chain); - -static gboolean gst_ogg_demux_perform_seek (GstOggDemux * ogg, - GstEvent * event); -static gboolean gst_ogg_demux_receive_event (GstElement * element, - GstEvent * event); - -static void gst_ogg_pad_class_init (GstOggPadClass * klass); -static void gst_ogg_pad_init (GstOggPad * pad); -static void gst_ogg_pad_dispose (GObject * object); -static void gst_ogg_pad_finalize (GObject * object); - -#if 0 -static const GstFormat *gst_ogg_pad_formats (GstPad * pad); -static const GstEventMask *gst_ogg_pad_event_masks (GstPad * pad); -#endif -static const GstQueryType *gst_ogg_pad_query_types (GstPad * pad); -static gboolean gst_ogg_pad_src_query (GstPad * pad, GstQuery * query); -static gboolean gst_ogg_pad_event (GstPad * pad, GstEvent * event); -static GstCaps *gst_ogg_pad_getcaps (GstPad * pad); -static GstOggPad *gst_ogg_chain_get_stream (GstOggChain * chain, - glong serialno); - -static gboolean gst_ogg_pad_query_convert (GstOggPad * pad, - GstFormat src_format, gint64 src_val, - GstFormat * dest_format, gint64 * dest_val); -static GstClockTime gst_annodex_granule_to_time (gint64 granulepos, - gint64 granulerate_n, gint64 granulerate_d, guint8 granuleshift); - -static GstFlowReturn gst_ogg_demux_combine_flows (GstOggDemux * ogg, - GstOggPad * pad, GstFlowReturn ret); - -static GstPadClass *ogg_pad_parent_class = NULL; - -static GType -gst_ogg_pad_get_type (void) -{ - static GType ogg_pad_type = 0; - - if (!ogg_pad_type) { - static const GTypeInfo ogg_pad_info = { - sizeof (GstOggPadClass), - NULL, - NULL, - (GClassInitFunc) gst_ogg_pad_class_init, - NULL, - NULL, - sizeof (GstOggPad), - 0, - (GInstanceInitFunc) gst_ogg_pad_init, - }; - - ogg_pad_type = - g_type_register_static (GST_TYPE_PAD, "GstOggPad", &ogg_pad_info, 0); - } - return ogg_pad_type; -} - -static void -gst_ogg_pad_class_init (GstOggPadClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - - ogg_pad_parent_class = g_type_class_peek_parent (klass); - - gobject_class->dispose = gst_ogg_pad_dispose; - gobject_class->finalize = gst_ogg_pad_finalize; -} - -static void -gst_ogg_pad_init (GstOggPad * pad) -{ - gst_pad_set_event_function (GST_PAD (pad), - GST_DEBUG_FUNCPTR (gst_ogg_pad_event)); - gst_pad_set_getcaps_function (GST_PAD (pad), - GST_DEBUG_FUNCPTR (gst_ogg_pad_getcaps)); - gst_pad_set_query_type_function (GST_PAD (pad), - GST_DEBUG_FUNCPTR (gst_ogg_pad_query_types)); - gst_pad_set_query_function (GST_PAD (pad), - GST_DEBUG_FUNCPTR (gst_ogg_pad_src_query)); - - pad->mode = GST_OGG_PAD_MODE_INIT; - - pad->first_granule = -1; - pad->current_granule = -1; - - pad->start_time = GST_CLOCK_TIME_NONE; - pad->first_time = GST_CLOCK_TIME_NONE; - - pad->have_type = FALSE; - pad->continued = NULL; - pad->headers = NULL; -} - -static void -gst_ogg_pad_dispose (GObject * object) -{ - GstOggPad *pad = GST_OGG_PAD (object); - GstPad **elem_pad_p; - GstElement **element_p; - GstPad **elem_out_p; - - if (pad->element) - gst_element_set_state (pad->element, GST_STATE_NULL); - - elem_pad_p = &pad->elem_pad; - element_p = &pad->element; - elem_out_p = &pad->elem_out; - gst_object_replace ((GstObject **) elem_pad_p, NULL); - gst_object_replace ((GstObject **) element_p, NULL); - gst_object_replace ((GstObject **) elem_out_p, NULL); - - pad->chain = NULL; - pad->ogg = NULL; - - g_list_foreach (pad->headers, (GFunc) gst_mini_object_unref, NULL); - g_list_free (pad->headers); - pad->headers = NULL; - - /* clear continued pages */ - g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL); - g_list_free (pad->continued); - pad->continued = NULL; - - ogg_stream_reset (&pad->stream); - - G_OBJECT_CLASS (ogg_pad_parent_class)->dispose (object); -} - -static void -gst_ogg_pad_finalize (GObject * object) -{ - GstOggPad *pad = GST_OGG_PAD (object); - - ogg_stream_clear (&pad->stream); - - G_OBJECT_CLASS (ogg_pad_parent_class)->finalize (object); -} - -#if 0 -static const GstFormat * -gst_ogg_pad_formats (GstPad * pad) -{ - static GstFormat src_formats[] = { - GST_FORMAT_DEFAULT, /* time */ - GST_FORMAT_TIME, /* granulepos */ - 0 - }; - static GstFormat sink_formats[] = { - GST_FORMAT_BYTES, - GST_FORMAT_DEFAULT, /* bytes */ - 0 - }; - - return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats); -} -#endif - -#if 0 -static const GstEventMask * -gst_ogg_pad_event_masks (GstPad * pad) -{ - static const GstEventMask src_event_masks[] = { - {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH}, - {0,} - }; - - return src_event_masks; -} -#endif - -static const GstQueryType * -gst_ogg_pad_query_types (GstPad * pad) -{ - static const GstQueryType query_types[] = { - GST_QUERY_DURATION, - GST_QUERY_SEEKING, - 0 - }; - - return query_types; -} - -static GstCaps * -gst_ogg_pad_getcaps (GstPad * pad) -{ - return gst_caps_ref (GST_PAD_CAPS (pad)); -} - -static gboolean -gst_ogg_pad_src_query (GstPad * pad, GstQuery * query) -{ - gboolean res = TRUE; - GstOggDemux *ogg; - GstOggPad *cur; - - ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad)); - cur = GST_OGG_PAD (pad); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_DURATION: - { - GstFormat format; - - gst_query_parse_duration (query, &format, NULL); - /* can only get position in time */ - if (format != GST_FORMAT_TIME) - goto wrong_format; - - /* can only return the total time position */ - /* FIXME, return time for this specific stream */ - gst_query_set_duration (query, GST_FORMAT_TIME, ogg->total_time); - break; - } - case GST_QUERY_SEEKING: - { - GstFormat format; - - gst_query_parse_seeking (query, &format, NULL, NULL, NULL); - if (format == GST_FORMAT_TIME) { - gst_query_set_seeking (query, GST_FORMAT_TIME, ogg->seekable, - 0, ogg->total_time); - } else { - res = FALSE; - } - break; - } - - default: - res = gst_pad_query_default (pad, query); - break; - } -done: - gst_object_unref (ogg); - - return res; - - /* ERRORS */ -wrong_format: - { - GST_DEBUG_OBJECT (ogg, "only query duration on TIME is supported"); - res = FALSE; - goto done; - } -} - -static gboolean -gst_ogg_demux_receive_event (GstElement * element, GstEvent * event) -{ - gboolean res; - GstOggDemux *ogg; - - ogg = GST_OGG_DEMUX (element); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - /* can't seek if we are not seekable, FIXME could pass the - * seek query upstream after converting it to bytes using - * the average bitrate of the stream. */ - if (!ogg->seekable) { - GST_DEBUG_OBJECT (ogg, "seek on non seekable stream"); - goto error; - } - - /* now do the seek */ - res = gst_ogg_demux_perform_seek (ogg, event); - gst_event_unref (event); - break; - default: - GST_DEBUG_OBJECT (ogg, "We only handle seek events here"); - goto error; - } - - return res; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (ogg, "error handling event"); - gst_event_unref (event); - return FALSE; - } -} - -static gboolean -gst_ogg_pad_event (GstPad * pad, GstEvent * event) -{ - gboolean res; - GstOggDemux *ogg; - GstOggPad *cur; - - ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad)); - cur = GST_OGG_PAD (pad); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - /* can't seek if we are not seekable, FIXME could pass the - * seek query upstream after converting it to bytes using - * the average bitrate of the stream. */ - if (!ogg->seekable) { - GST_DEBUG_OBJECT (ogg, "seek on non seekable stream"); - goto error; - } - - /* now do the seek */ - res = gst_ogg_demux_perform_seek (ogg, event); - gst_event_unref (event); - break; - default: - res = gst_pad_event_default (pad, event); - break; - } -done: - gst_object_unref (ogg); - - return res; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (ogg, "error handling event"); - gst_event_unref (event); - res = FALSE; - goto done; - } -} - -static void -gst_ogg_pad_reset (GstOggPad * pad) -{ - ogg_stream_reset (&pad->stream); - - /* clear continued pages */ - g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL); - g_list_free (pad->continued); - pad->continued = NULL; - - pad->last_ret = GST_FLOW_OK; -} - -/* the filter function for selecting the elements we can use in - * autoplugging */ -static gboolean -gst_ogg_demux_factory_filter (GstPluginFeature * feature, GstCaps * caps) -{ - guint rank; - const gchar *klass; - - /* we only care about element factories */ - if (!GST_IS_ELEMENT_FACTORY (feature)) - return FALSE; - - klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature)); - /* only demuxers and decoders can play */ - if (strstr (klass, "Demux") == NULL && - strstr (klass, "Decoder") == NULL && strstr (klass, "Parse") == NULL) { - return FALSE; - } - - /* only select elements with autoplugging rank */ - rank = gst_plugin_feature_get_rank (feature); - if (rank < GST_RANK_MARGINAL) - return FALSE; - - GST_DEBUG ("checking factory %s", GST_PLUGIN_FEATURE_NAME (feature)); - /* now see if it is compatible with the caps */ - { - GstElementFactory *factory = GST_ELEMENT_FACTORY (feature); - const GList *templates; - GList *walk; - - /* get the templates from the element factory */ - templates = gst_element_factory_get_static_pad_templates (factory); - - for (walk = (GList *) templates; walk; walk = g_list_next (walk)) { - GstStaticPadTemplate *templ = walk->data; - - /* we only care about the sink templates */ - if (templ->direction == GST_PAD_SINK) { - GstCaps *intersect; - GstCaps *scaps; - gboolean empty; - - /* try to intersect the caps with the caps of the template */ - scaps = gst_static_caps_get (&templ->static_caps); - intersect = gst_caps_intersect (caps, scaps); - gst_caps_unref (scaps); - - empty = gst_caps_is_empty (intersect); - gst_caps_unref (intersect); - - /* check if the intersection is empty */ - if (!empty) { - /* non empty intersection, we can use this element */ - goto found; - } - } - } - } - return FALSE; - -found: - return TRUE; -} - -/* function used to sort element features */ -static gint -compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2) -{ - gint diff; - - diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1); - if (diff != 0) - return diff; - return strcmp (gst_plugin_feature_get_name (f2), - gst_plugin_feature_get_name (f1)); -} - -/* called when the skeleton fishead is found. Caller ensures the packet is - * precisely the correct size; we don't re-check this here. */ -static void -gst_ogg_pad_parse_skeleton_fishead (GstOggPad * pad, ogg_packet * packet) -{ - GstOggDemux *ogg = pad->ogg; - guint8 *data = packet->packet; - guint16 major, minor; - gint64 prestime_n, prestime_d; - gint64 basetime_n, basetime_d; - - /* skip "fishead\0" */ - data += 8; - major = GST_READ_UINT16_LE (data); - data += 2; - minor = GST_READ_UINT16_LE (data); - data += 2; - prestime_n = (gint64) GST_READ_UINT64_LE (data); - data += 8; - prestime_d = (gint64) GST_READ_UINT64_LE (data); - data += 8; - basetime_n = (gint64) GST_READ_UINT64_LE (data); - data += 8; - basetime_d = (gint64) GST_READ_UINT64_LE (data); - data += 8; - - ogg->basetime = gst_util_uint64_scale (GST_SECOND, basetime_n, basetime_d); - ogg->have_fishead = TRUE; - pad->is_skeleton = TRUE; - pad->start_time = GST_CLOCK_TIME_NONE; - pad->first_granule = -1; - pad->first_time = GST_CLOCK_TIME_NONE; - GST_INFO_OBJECT (ogg, "skeleton fishead parsed (basetime: %" - GST_TIME_FORMAT ")", GST_TIME_ARGS (ogg->basetime)); -} - -/* function called when a skeleton fisbone is found. Caller ensures that - * the packet length is sufficient */ -static void -gst_ogg_pad_parse_skeleton_fisbone (GstOggPad * pad, ogg_packet * packet) -{ - GstOggPad *fisbone_pad; - gint64 start_granule; - guint32 serialno; - guint8 *data = packet->packet; - - /* skip "fisbone\0" */ - data += 8; - /* skip headers offset */ - data += 4; - serialno = GST_READ_UINT32_LE (data); - - fisbone_pad = gst_ogg_chain_get_stream (pad->chain, serialno); - if (fisbone_pad) { - if (fisbone_pad->have_fisbone) - /* already parsed */ - return; - - fisbone_pad->have_fisbone = TRUE; - - data += 4; - /* skip number of headers */ - data += 4; - fisbone_pad->granulerate_n = GST_READ_UINT64_LE (data); - data += 8; - fisbone_pad->granulerate_d = GST_READ_UINT64_LE (data); - data += 8; - start_granule = GST_READ_UINT64_LE (data); - data += 8; - fisbone_pad->preroll = GST_READ_UINT32_LE (data); - data += 4; - fisbone_pad->granuleshift = GST_READ_UINT8 (data); - data += 1; - /* padding */ - data += 3; - - fisbone_pad->start_time = gst_annodex_granule_to_time (start_granule, - fisbone_pad->granulerate_n, fisbone_pad->granulerate_d, - fisbone_pad->granuleshift); - - GST_INFO_OBJECT (pad->ogg, "skeleton fisbone parsed " - "(serialno: %08x start time: %" GST_TIME_FORMAT - " granulerate_n: %" G_GINT64_FORMAT " granulerate_d: %" G_GINT64_FORMAT - " preroll: %" G_GUINT32_FORMAT " granuleshift: %d)", - serialno, GST_TIME_ARGS (fisbone_pad->start_time), - fisbone_pad->granulerate_n, fisbone_pad->granulerate_d, - fisbone_pad->preroll, fisbone_pad->granuleshift); - } else { - GST_WARNING_OBJECT (pad->ogg, - "found skeleton fisbone for an unknown stream %" G_GUINT32_FORMAT, - serialno); - } -} - -/* function called to convert a granulepos to a timestamp */ -static gboolean -gst_ogg_pad_query_convert (GstOggPad * pad, GstFormat src_format, - gint64 src_val, GstFormat * dest_format, gint64 * dest_val) -{ - gboolean res; - - if (src_val == -1) { - *dest_val = -1; - return TRUE; - } - - if (!pad->have_fisbone && pad->elem_pad == NULL) - return FALSE; - - switch (src_format) { - case GST_FORMAT_DEFAULT: - if (pad->have_fisbone && *dest_format == GST_FORMAT_TIME) { - *dest_val = gst_annodex_granule_to_time (src_val, - pad->granulerate_n, pad->granulerate_d, pad->granuleshift); - - res = TRUE; - } else { - if (pad->elem_pad == NULL) - res = FALSE; - else - res = gst_pad_query_convert (pad->elem_pad, src_format, src_val, - dest_format, dest_val); - } - - break; - default: - if (pad->elem_pad == NULL) - res = FALSE; - else - res = gst_pad_query_convert (pad->elem_pad, src_format, src_val, - dest_format, dest_val); - } - - return res; -} - -/* function called by the internal decoder elements when it outputs - * a buffer. We use it to get the first timestamp of the stream - */ -static GstFlowReturn -gst_ogg_pad_internal_chain (GstPad * pad, GstBuffer * buffer) -{ - GstOggPad *oggpad; - GstOggDemux *ogg; - GstClockTime timestamp; - - oggpad = gst_pad_get_element_private (pad); - ogg = GST_OGG_DEMUX (oggpad->ogg); - - timestamp = GST_BUFFER_TIMESTAMP (buffer); - GST_DEBUG_OBJECT (oggpad, "received buffer from internal pad, TS=%" - GST_TIME_FORMAT "=%" G_GINT64_FORMAT, GST_TIME_ARGS (timestamp), - timestamp); - - if (oggpad->start_time == GST_CLOCK_TIME_NONE) { - oggpad->start_time = timestamp; - GST_DEBUG_OBJECT (oggpad, "new start time: %" GST_TIME_FORMAT, - GST_TIME_ARGS (timestamp)); - } - - gst_buffer_unref (buffer); - - return GST_FLOW_OK; -} - -static void -internal_element_pad_added_cb (GstElement * element, GstPad * pad, - GstOggPad * oggpad) -{ - if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { - if (!(gst_pad_link (pad, oggpad->elem_out) == GST_PAD_LINK_OK)) { - GST_ERROR ("Really couldn't find a valid pad"); - } - oggpad->dynamic = FALSE; - g_signal_handler_disconnect (element, oggpad->padaddedid); - oggpad->padaddedid = 0; - } -} - -/* runs typefind on the packet, which is assumed to be the first - * packet in the stream. - * - * Based on the type returned from the typefind function, an element - * is created to help in conversion between granulepos and timestamps - * so that we can do decent seeking. - */ -static gboolean -gst_ogg_pad_typefind (GstOggPad * pad, ogg_packet * packet) -{ - GstBuffer *buf; - GstCaps *caps; - GstElement *element = NULL; - -#ifndef GST_DISABLE_GST_DEBUG - GstOggDemux *ogg = pad->ogg; -#endif - - if (GST_PAD_CAPS (pad) != NULL) - return TRUE; - - /* The ogg spec defines that the first packet of an ogg stream must identify - * the stream. Therefore ogg can use a simplified approach to typefinding - * and only needs to check the first packet */ - buf = gst_buffer_new (); - GST_BUFFER_DATA (buf) = packet->packet; - GST_BUFFER_SIZE (buf) = packet->bytes; - GST_BUFFER_OFFSET (buf) = 0; - - caps = gst_type_find_helper_for_buffer (GST_OBJECT (pad), buf, NULL); - gst_buffer_unref (buf); - - if (caps == NULL) { - GST_WARNING_OBJECT (ogg, - "couldn't find caps for stream with serial %08x", pad->serialno); - caps = gst_caps_new_simple ("application/octet-stream", NULL); - } else { - /* ogg requires you to use a decoder element to define the - * meaning of granulepos etc so we make one. We also do this if - * we are in the streaming mode to calculate the first timestamp. */ - GList *factories; - - GST_LOG_OBJECT (ogg, "found caps: %" GST_PTR_FORMAT, caps); - - /* first filter out the interesting element factories */ - factories = gst_default_registry_feature_filter ( - (GstPluginFeatureFilter) gst_ogg_demux_factory_filter, FALSE, caps); - - /* sort them according to their ranks */ - factories = g_list_sort (factories, (GCompareFunc) compare_ranks); - - /* then pick the first factory to create an element */ - if (factories) { - element = - gst_element_factory_create (GST_ELEMENT_FACTORY (factories->data), - NULL); - if (element) { - GstPadTemplate *template; - - /* this is ours */ - gst_object_ref (element); - gst_object_sink (GST_OBJECT (element)); - - /* FIXME, it might not be named "sink" */ - pad->elem_pad = gst_element_get_pad (element, "sink"); - gst_element_set_state (element, GST_STATE_PAUSED); - template = gst_static_pad_template_get (&internaltemplate); - pad->elem_out = gst_pad_new_from_template (template, "internal"); - gst_pad_set_chain_function (pad->elem_out, gst_ogg_pad_internal_chain); - gst_pad_set_element_private (pad->elem_out, pad); - gst_pad_set_active (pad->elem_out, TRUE); - gst_object_unref (template); - - /* and this pad may not be named src.. */ - /* And it might also not exist at this time... */ - { - GstPad *p; - - p = gst_element_get_pad (element, "src"); - if (p) { - gst_pad_link (p, pad->elem_out); - gst_object_unref (p); - } else { - pad->dynamic = TRUE; - pad->padaddedid = g_signal_connect (G_OBJECT (element), - "pad-added", G_CALLBACK (internal_element_pad_added_cb), pad); - } - } - } - } - g_list_free (factories); - } - pad->element = element; - - gst_pad_set_caps (GST_PAD (pad), caps); - gst_caps_unref (caps); - - return TRUE; -} - -/* send packet to internal element */ -static GstFlowReturn -gst_ogg_demux_chain_elem_pad (GstOggPad * pad, ogg_packet * packet) -{ - GstBuffer *buf; - GstFlowReturn ret; - -#ifndef GST_DISABLE_GST_DEBUG - GstOggDemux *ogg = pad->ogg; -#endif - - /* initialize our internal decoder with packets */ - if (!pad->elem_pad) - goto no_decoder; - - GST_DEBUG_OBJECT (ogg, "%p init decoder serial %08x", pad, pad->serialno); - - buf = gst_buffer_new_and_alloc (packet->bytes); - memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes); - gst_buffer_set_caps (buf, GST_PAD_CAPS (pad)); - GST_BUFFER_OFFSET (buf) = -1; - GST_BUFFER_OFFSET_END (buf) = packet->granulepos; - - ret = gst_pad_chain (pad->elem_pad, buf); - if (GST_FLOW_IS_FATAL (ret)) - goto decoder_error; - - return ret; - -no_decoder: - { - GST_WARNING_OBJECT (ogg, - "pad %p does not have elem_pad, no decoder ?", pad); - return GST_FLOW_ERROR; - } -decoder_error: - { - GST_WARNING_OBJECT (ogg, "internal decoder error"); - return GST_FLOW_ERROR; - } -} - -/* queue data, basically takes the packet, puts it in a buffer and store the - * buffer in the headers list. - */ -static GstFlowReturn -gst_ogg_demux_queue_data (GstOggPad * pad, ogg_packet * packet) -{ - GstBuffer *buf; - -#ifndef GST_DISABLE_GST_DEBUG - GstOggDemux *ogg = pad->ogg; -#endif - - GST_DEBUG_OBJECT (ogg, "%p queueing data serial %08x", pad, pad->serialno); - - buf = gst_buffer_new_and_alloc (packet->bytes); - memcpy (buf->data, packet->packet, packet->bytes); - GST_BUFFER_OFFSET (buf) = -1; - GST_BUFFER_OFFSET_END (buf) = packet->granulepos; - pad->headers = g_list_append (pad->headers, buf); - - /* we are ok now */ - return GST_FLOW_OK; -} - -/* send packet to internal element */ -static GstFlowReturn -gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet) -{ - GstBuffer *buf; - GstFlowReturn ret, cret; - GstOggDemux *ogg = pad->ogg; - GstFormat format; - gint64 current_time; - GstOggChain *chain; - - GST_DEBUG_OBJECT (ogg, - "%p streaming to peer serial %08x", pad, pad->serialno); - - ret = - gst_pad_alloc_buffer_and_set_caps (GST_PAD_CAST (pad), - GST_BUFFER_OFFSET_NONE, packet->bytes, GST_PAD_CAPS (pad), &buf); - - /* combine flows */ - cret = gst_ogg_demux_combine_flows (ogg, pad, ret); - if (ret != GST_FLOW_OK) - goto no_buffer; - - /* copy packet in buffer */ - memcpy (buf->data, packet->packet, packet->bytes); - - GST_BUFFER_OFFSET (buf) = -1; - GST_BUFFER_OFFSET_END (buf) = packet->granulepos; - - /* Mark discont on the buffer */ - if (pad->discont) { - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - pad->discont = FALSE; - } - - ret = gst_pad_push (GST_PAD_CAST (pad), buf); - - /* combine flows */ - cret = gst_ogg_demux_combine_flows (ogg, pad, ret); - - /* we're done with skeleton stuff */ - if (pad->is_skeleton) - goto done; - - /* check if valid granulepos, then we can calculate the current - * position */ - if (packet->granulepos < 0) - goto done; - - /* store current granule pos */ - ogg->current_granule = packet->granulepos; - - /* convert to time */ - format = GST_FORMAT_TIME; - if (!gst_ogg_pad_query_convert (pad, - GST_FORMAT_DEFAULT, packet->granulepos, &format, - (gint64 *) & current_time)) - goto convert_failed; - - /* convert to stream time */ - if ((chain = pad->chain)) - current_time = current_time - chain->segment_start + chain->begin_time; - - /* and store as the current position */ - gst_segment_set_last_stop (&ogg->segment, GST_FORMAT_TIME, current_time); - - GST_DEBUG_OBJECT (ogg, "ogg current time %" GST_TIME_FORMAT, - GST_TIME_ARGS (current_time)); - -done: - /* return combined flow result */ - return cret; - - /* special cases */ -no_buffer: - { - GST_DEBUG_OBJECT (ogg, - "%p could not get buffer from peer %08x, %d (%s), combined %d (%s)", - pad, pad->serialno, ret, gst_flow_get_name (ret), - cret, gst_flow_get_name (cret)); - goto done; - } -convert_failed: - { - GST_WARNING_OBJECT (ogg, "could not convert granulepos to time"); - goto done; - } -} - -/* submit a packet to the oggpad, this function will run the - * typefind code for the pad if this is the first packet for this - * stream - */ -static GstFlowReturn -gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet) -{ - gint64 granule; - GstFlowReturn ret; - - GstOggDemux *ogg = pad->ogg; - - GST_DEBUG_OBJECT (ogg, "%p submit packet serial %08x", pad, pad->serialno); - - if (!pad->have_type) { - if (!ogg->have_fishead && packet->bytes == SKELETON_FISHEAD_SIZE && - !memcmp (packet->packet, "fishead\0", 8)) { - gst_ogg_pad_parse_skeleton_fishead (pad, packet); - } - gst_ogg_pad_typefind (pad, packet); - pad->have_type = TRUE; - } - - if (ogg->have_fishead && packet->bytes >= SKELETON_FISBONE_MIN_SIZE && - !memcmp (packet->packet, "fisbone\0", 8)) { - gst_ogg_pad_parse_skeleton_fisbone (pad, packet); - } - - granule = packet->granulepos; - if (granule != -1) { - GST_DEBUG_OBJECT (ogg, "%p has granulepos %" G_GINT64_FORMAT, pad, granule); - ogg->current_granule = granule; - pad->current_granule = granule; - /* granulepos 0 and -1 are considered header packets. - * Note that since theora is busted, it can create non-header - * packets with 0 granulepos. We will correct for this when our - * internal decoder produced a frame and we don't have a - * granulepos because in that case the granulpos must have been 0 */ - if (pad->first_granule == -1 && granule != 0) { - GST_DEBUG_OBJECT (ogg, "%p found first granulepos %" G_GINT64_FORMAT, pad, - granule); - pad->first_granule = granule; - } - } - - if (granule != -1 && memcmp (packet->packet, "KW-DIRAC", 8) == 0) { - return GST_FLOW_OK; - } - - /* no start time known, stream to internal plugin to - * get time. always stream to the skeleton decoder */ - if (pad->start_time == GST_CLOCK_TIME_NONE || pad->is_skeleton) { - ret = gst_ogg_demux_chain_elem_pad (pad, packet); - } - /* we know the start_time of the pad data, see if we - * can activate the complete chain if this is a dynamic - * chain. */ - if (pad->start_time != GST_CLOCK_TIME_NONE) { - GstOggChain *chain = pad->chain; - - /* correction for busted ogg, if the internal decoder outputed - * a timestamp but we did not get a granulepos, it must have - * been 0 and the time is therefore also 0 */ - if (pad->first_granule == -1) { - GST_DEBUG_OBJECT (ogg, "%p found start time without granulepos", pad); - pad->first_granule = 0; - pad->first_time = 0; - } - - /* check if complete chain has start time */ - if (chain == ogg->building_chain) { - - /* see if we have enough info to activate the chain, we have enough info - * when all streams have a valid start time. */ - if (gst_ogg_demux_collect_chain_info (ogg, chain)) { - GstEvent *event; - - GST_DEBUG_OBJECT (ogg, "segment_start: %" GST_TIME_FORMAT, - GST_TIME_ARGS (chain->segment_start)); - GST_DEBUG_OBJECT (ogg, "segment_stop: %" GST_TIME_FORMAT, - GST_TIME_ARGS (chain->segment_stop)); - GST_DEBUG_OBJECT (ogg, "segment_time: %" GST_TIME_FORMAT, - GST_TIME_ARGS (chain->begin_time)); - - /* create the newsegment event we are going to send out */ - event = gst_event_new_new_segment (FALSE, ogg->segment.rate, - GST_FORMAT_TIME, chain->segment_start, chain->segment_stop, - chain->begin_time); - - gst_ogg_demux_activate_chain (ogg, chain, event); - - ogg->building_chain = NULL; - } - } - } - - /* if we are building a chain, store buffer for when we activate - * it. This path is taken if we operate in streaming mode. */ - if (ogg->building_chain) { - ret = gst_ogg_demux_queue_data (pad, packet); - } - /* else we are completely streaming to the peer */ - else { - ret = gst_ogg_demux_chain_peer (pad, packet); - } - return ret; -} - -/* flush at most @npackets from the stream layer. All packets if - * @npackets is 0; - */ -static GstFlowReturn -gst_ogg_pad_stream_out (GstOggPad * pad, gint npackets) -{ - GstFlowReturn result = GST_FLOW_OK; - gboolean done = FALSE; - GstOggDemux *ogg; - - ogg = pad->ogg; - - while (!done) { - int ret; - ogg_packet packet; - - ret = ogg_stream_packetout (&pad->stream, &packet); - switch (ret) { - case 0: - GST_LOG_OBJECT (ogg, "packetout done"); - done = TRUE; - break; - case -1: - GST_LOG_OBJECT (ogg, "packetout discont"); - gst_ogg_chain_mark_discont (pad->chain); - break; - case 1: - GST_LOG_OBJECT (ogg, "packetout gave packet of size %ld", packet.bytes); - result = gst_ogg_pad_submit_packet (pad, &packet); - if (GST_FLOW_IS_FATAL (result)) - goto could_not_submit; - break; - default: - GST_WARNING_OBJECT (ogg, - "invalid return value %d for ogg_stream_packetout, resetting stream", - ret); - gst_ogg_pad_reset (pad); - break; - } - if (npackets > 0) { - npackets--; - done = (npackets == 0); - } - } - return result; - - /* ERRORS */ -could_not_submit: - { - GST_WARNING_OBJECT (ogg, - "could not submit packet for stream %08x, error: %d", pad->serialno, - result); - gst_ogg_pad_reset (pad); - return result; - } -} - -/* submit a page to an oggpad, this function will then submit all - * the packets in the page. - */ -static GstFlowReturn -gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page) -{ - GstFlowReturn result = GST_FLOW_OK; - GstOggDemux *ogg; - gboolean continued = FALSE; - - ogg = pad->ogg; - - /* for negative rates we read pages backwards and must therefore be carefull - * with continued pages */ - if (ogg->segment.rate < 0.0) { - gint npackets; - - continued = ogg_page_continued (page); - - /* number of completed packets in the page */ - npackets = ogg_page_packets (page); - if (!continued) { - /* page is not continued so it contains at least one packet start. It's - * possible that no packet ends on this page (npackets == 0). In that - * case, the next (continued) page(s) we kept contain the remainder of the - * packets. We mark npackets=1 to make us start decoding the pages in the - * remainder of the algorithm. */ - if (npackets == 0) - npackets = 1; - } - GST_LOG_OBJECT (ogg, "continued: %d, %d packets", continued, npackets); - - if (npackets == 0) { - GST_LOG_OBJECT (ogg, "no decodable packets, we need a previous page"); - goto done; - } - } - - if (ogg_stream_pagein (&pad->stream, page) != 0) - goto choked; - - /* flush all packets in the stream layer, this might not give a packet if - * the page had no packets finishing on the page (npackets == 0). */ - result = gst_ogg_pad_stream_out (pad, 0); - - if (pad->continued) { - ogg_packet packet; - - /* now send the continued pages to the stream layer */ - while (pad->continued) { - ogg_page *p = (ogg_page *) pad->continued->data; - - GST_LOG_OBJECT (ogg, "submitting continued page %p", p); - if (ogg_stream_pagein (&pad->stream, p) != 0) - goto choked; - - pad->continued = g_list_delete_link (pad->continued, pad->continued); - - /* free the page */ - gst_ogg_page_free (p); - } - - GST_LOG_OBJECT (ogg, "flushing last continued packet"); - /* flush 1 continued packet in the stream layer */ - result = gst_ogg_pad_stream_out (pad, 1); - - /* flush all remaining packets, we pushed them in the previous round. - * We don't use _reset() because we still want to get the discont when - * we submit a next page. */ - while (ogg_stream_packetout (&pad->stream, &packet) != 0); - } - -done: - /* keep continued pages (only in reverse mode) */ - if (continued) { - ogg_page *p = gst_ogg_page_copy (page); - - GST_LOG_OBJECT (ogg, "keeping continued page %p", p); - pad->continued = g_list_prepend (pad->continued, p); - } - - return result; - -choked: - { - GST_WARNING_OBJECT (ogg, - "ogg stream choked on page (serial %08x), resetting stream", - pad->serialno); - gst_ogg_pad_reset (pad); - /* we continue to recover */ - return GST_FLOW_OK; - } -} - - -static GstOggChain * -gst_ogg_chain_new (GstOggDemux * ogg) -{ - GstOggChain *chain = g_new0 (GstOggChain, 1); - - GST_DEBUG_OBJECT (ogg, "creating new chain %p", chain); - chain->ogg = ogg; - chain->offset = -1; - chain->bytes = -1; - chain->have_bos = FALSE; - chain->streams = g_array_new (FALSE, TRUE, sizeof (GstOggPad *)); - chain->begin_time = GST_CLOCK_TIME_NONE; - chain->segment_start = GST_CLOCK_TIME_NONE; - chain->segment_stop = GST_CLOCK_TIME_NONE; - chain->total_time = GST_CLOCK_TIME_NONE; - - return chain; -} - -static void -gst_ogg_chain_free (GstOggChain * chain) -{ - gint i; - - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - - gst_object_unref (pad); - } - g_array_free (chain->streams, TRUE); - g_free (chain); -} - -static void -gst_ogg_chain_mark_discont (GstOggChain * chain) -{ - gint i; - - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - - pad->discont = TRUE; - } -} - -static void -gst_ogg_chain_reset (GstOggChain * chain) -{ - gint i; - - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - - gst_ogg_pad_reset (pad); - } -} - -static GstOggPad * -gst_ogg_chain_new_stream (GstOggChain * chain, glong serialno) -{ - GstOggPad *ret; - GstTagList *list; - gchar *name; - - GST_DEBUG_OBJECT (chain->ogg, "creating new stream %08lx in chain %p", - serialno, chain); - - ret = g_object_new (GST_TYPE_OGG_PAD, NULL); - /* we own this one */ - gst_object_ref (ret); - gst_object_sink (ret); - - GST_PAD_DIRECTION (ret) = GST_PAD_SRC; - ret->discont = TRUE; - - ret->chain = chain; - ret->ogg = chain->ogg; - - ret->serialno = serialno; - if (ogg_stream_init (&ret->stream, serialno) != 0) - goto init_failed; - - name = g_strdup_printf ("serial_%08lx", serialno); - gst_object_set_name (GST_OBJECT (ret), name); - g_free (name); - - /* FIXME: either do something with it or remove it */ - list = gst_tag_list_new (); - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SERIAL, serialno, - NULL); - gst_tag_list_free (list); - - GST_DEBUG_OBJECT (chain->ogg, - "created new ogg src %p for stream with serial %08lx", ret, serialno); - - g_array_append_val (chain->streams, ret); - - return ret; - - /* ERRORS */ -init_failed: - { - GST_ERROR ("Could not initialize ogg_stream struct for serial %08lx.", - serialno); - gst_object_unref (ret); - return NULL; - } -} - -static GstOggPad * -gst_ogg_chain_get_stream (GstOggChain * chain, glong serialno) -{ - gint i; - - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - - if (pad->serialno == serialno) - return pad; - } - return NULL; -} - -static gboolean -gst_ogg_chain_has_stream (GstOggChain * chain, glong serialno) -{ - return gst_ogg_chain_get_stream (chain, serialno) != NULL; -} - -#define CURRENT_CHAIN(ogg) (&g_array_index ((ogg)->chains, GstOggChain, (ogg)->current_chain)) - -/* signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0 - /* FILL ME */ -}; - -static GstStaticPadTemplate ogg_demux_src_template_factory = -GST_STATIC_PAD_TEMPLATE ("src_%d", - GST_PAD_SRC, - GST_PAD_SOMETIMES, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate ogg_demux_sink_template_factory = - GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/ogg; application/x-annodex") - ); - -static void gst_ogg_demux_finalize (GObject * object); - -//static const GstEventMask *gst_ogg_demux_get_event_masks (GstPad * pad); -//static const GstQueryType *gst_ogg_demux_get_query_types (GstPad * pad); -static GstFlowReturn gst_ogg_demux_read_chain (GstOggDemux * ogg, - GstOggChain ** chain); -static GstFlowReturn gst_ogg_demux_read_end_chain (GstOggDemux * ogg, - GstOggChain * chain); - -static gboolean gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event); -static void gst_ogg_demux_loop (GstOggPad * pad); -static GstFlowReturn gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_ogg_demux_sink_activate (GstPad * sinkpad); -static gboolean gst_ogg_demux_sink_activate_pull (GstPad * sinkpad, - gboolean active); -static gboolean gst_ogg_demux_sink_activate_push (GstPad * sinkpad, - gboolean active); -static GstStateChangeReturn gst_ogg_demux_change_state (GstElement * element, - GstStateChange transition); -static void gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event); - -static void gst_ogg_print (GstOggDemux * demux); - -GST_BOILERPLATE (GstOggDemux, gst_ogg_demux, GstElement, GST_TYPE_ELEMENT); - -static void -gst_ogg_demux_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_ogg_demux_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&ogg_demux_sink_template_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&ogg_demux_src_template_factory)); -} -static void -gst_ogg_demux_class_init (GstOggDemuxClass * klass) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gstelement_class->change_state = gst_ogg_demux_change_state; - gstelement_class->send_event = gst_ogg_demux_receive_event; - - gobject_class->finalize = gst_ogg_demux_finalize; -} - -static void -gst_ogg_demux_init (GstOggDemux * ogg, GstOggDemuxClass * g_class) -{ - /* create the sink pad */ - ogg->sinkpad = - gst_pad_new_from_static_template (&ogg_demux_sink_template_factory, - "sink"); - - gst_pad_set_event_function (ogg->sinkpad, gst_ogg_demux_sink_event); - gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_demux_chain); - gst_pad_set_activate_function (ogg->sinkpad, gst_ogg_demux_sink_activate); - gst_pad_set_activatepull_function (ogg->sinkpad, - gst_ogg_demux_sink_activate_pull); - gst_pad_set_activatepush_function (ogg->sinkpad, - gst_ogg_demux_sink_activate_push); - gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad); - - ogg->chain_lock = g_mutex_new (); - ogg->chains = g_array_new (FALSE, TRUE, sizeof (GstOggChain *)); - - ogg->newsegment = NULL; -} - -static void -gst_ogg_demux_finalize (GObject * object) -{ - GstOggDemux *ogg; - - ogg = GST_OGG_DEMUX (object); - - g_array_free (ogg->chains, TRUE); - g_mutex_free (ogg->chain_lock); - ogg_sync_clear (&ogg->sync); - - if (ogg->newsegment) - gst_event_unref (ogg->newsegment); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event) -{ - gboolean res; - GstOggDemux *ogg; - - ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - /* FIXME */ - GST_DEBUG_OBJECT (ogg, "got a new segment event"); - ogg_sync_reset (&ogg->sync); - gst_event_unref (event); - res = TRUE; - break; - case GST_EVENT_EOS: - default: - res = gst_pad_event_default (pad, event); - break; - } - gst_object_unref (ogg); - - return res; -} - -/* submit the given buffer to the ogg sync. - * - * Returns the number of bytes submited. - */ -static GstFlowReturn -gst_ogg_demux_submit_buffer (GstOggDemux * ogg, GstBuffer * buffer) -{ - gint size; - guint8 *data; - gchar *oggbuffer; - GstFlowReturn ret = GST_FLOW_OK; - - size = GST_BUFFER_SIZE (buffer); - data = GST_BUFFER_DATA (buffer); - - GST_DEBUG_OBJECT (ogg, "submitting %u bytes", size); - if (G_UNLIKELY (size == 0)) - goto done; - - oggbuffer = ogg_sync_buffer (&ogg->sync, size); - if (G_UNLIKELY (oggbuffer == NULL)) - goto no_buffer; - - memcpy (oggbuffer, data, size); - if (G_UNLIKELY (ogg_sync_wrote (&ogg->sync, size) < 0)) - goto write_failed; - -done: - gst_buffer_unref (buffer); - - return ret; - - /* ERRORS */ -no_buffer: - { - GST_ELEMENT_ERROR (ogg, STREAM, DECODE, - (NULL), ("failed to get ogg sync buffer")); - ret = GST_FLOW_ERROR; - goto done; - } -write_failed: - { - GST_ELEMENT_ERROR (ogg, STREAM, DECODE, - (NULL), ("failed to write %d bytes to the sync buffer", size)); - ret = GST_FLOW_ERROR; - goto done; - } -} - -/* in random access mode this code updates the current read position - * and resets the ogg sync buffer so that the next read will happen - * from this new location. - */ -static void -gst_ogg_demux_seek (GstOggDemux * ogg, gint64 offset) -{ - GST_LOG_OBJECT (ogg, "seeking to %" G_GINT64_FORMAT, offset); - - ogg->offset = offset; - ogg_sync_reset (&ogg->sync); -} - -/* read more data from the current offset and submit to - * the ogg sync layer. - */ -static GstFlowReturn -gst_ogg_demux_get_data (GstOggDemux * ogg) -{ - GstFlowReturn ret; - GstBuffer *buffer; - - GST_LOG_OBJECT (ogg, "get data %" G_GINT64_FORMAT " %" G_GINT64_FORMAT, - ogg->offset, ogg->length); - if (ogg->offset == ogg->length) - goto eos; - - ret = gst_pad_pull_range (ogg->sinkpad, ogg->offset, CHUNKSIZE, &buffer); - if (ret != GST_FLOW_OK) - goto error; - - ret = gst_ogg_demux_submit_buffer (ogg, buffer); - - return ret; - - /* ERROR */ -eos: - { - GST_LOG_OBJECT (ogg, "reached EOS"); - return GST_FLOW_UNEXPECTED; - } -error: - { - GST_WARNING_OBJECT (ogg, "got %d (%s) from pull range", ret, - gst_flow_get_name (ret)); - return ret; - } -} - -/* Read the next page from the current offset. - * boundary: number of bytes ahead we allow looking for; - * -1 if no boundary - * - * @offset will contain the offset the next page starts at when this function - * returns GST_FLOW_OK. - * - * GST_FLOW_UNEXPECTED is returned on EOS. - * - * GST_FLOW_LIMIT is returned when we did not find a page before the - * boundary. If @boundary is -1, this is never returned. - * - * Any other error returned while retrieving data from the peer is returned as - * is. - */ -static GstFlowReturn -gst_ogg_demux_get_next_page (GstOggDemux * ogg, ogg_page * og, gint64 boundary, - gint64 * offset) -{ - gint64 end_offset = 0; - GstFlowReturn ret; - - GST_LOG_OBJECT (ogg, - "get next page, current offset %" G_GINT64_FORMAT ", bytes boundary %" - G_GINT64_FORMAT, ogg->offset, boundary); - - if (boundary > 0) - end_offset = ogg->offset + boundary; - - while (TRUE) { - glong more; - - if (boundary > 0 && ogg->offset >= end_offset) - goto boundary_reached; - - more = ogg_sync_pageseek (&ogg->sync, og); - - GST_LOG_OBJECT (ogg, "pageseek gave %ld", more); - - if (more < 0) { - /* skipped n bytes */ - GST_LOG_OBJECT (ogg, "skipped %ld bytes", more); - ogg->offset -= more; - } else if (more == 0) { - /* we need more data */ - if (boundary == 0) - goto boundary_reached; - - GST_LOG_OBJECT (ogg, "need more data"); - ret = gst_ogg_demux_get_data (ogg); - if (ret != GST_FLOW_OK) - break; - } else { - gint64 res_offset = ogg->offset; - - /* got a page. Return the offset at the page beginning, - advance the internal offset past the page end */ - if (offset) - *offset = res_offset; - ret = GST_FLOW_OK; - - ogg->offset += more; - /* need to reset as we do not keep track of the bytes we - * sent to the sync layer */ - ogg_sync_reset (&ogg->sync); - - GST_LOG_OBJECT (ogg, - "got page at %" G_GINT64_FORMAT ", serial %08x, end at %" - G_GINT64_FORMAT ", granule %" G_GINT64_FORMAT, res_offset, - ogg_page_serialno (og), ogg->offset, ogg_page_granulepos (og)); - break; - } - } - GST_LOG_OBJECT (ogg, "returning %d", ret); - - return ret; - - /* ERRORS */ -boundary_reached: - { - GST_LOG_OBJECT (ogg, - "offset %" G_GINT64_FORMAT " >= end_offset %" G_GINT64_FORMAT, - ogg->offset, end_offset); - return GST_FLOW_LIMIT; - } -} - -/* from the current offset, find the previous page, seeking backwards - * until we find the page. - */ -static GstFlowReturn -gst_ogg_demux_get_prev_page (GstOggDemux * ogg, ogg_page * og, gint64 * offset) -{ - GstFlowReturn ret; - gint64 begin = ogg->offset; - gint64 end = begin; - gint64 cur_offset = -1; - - while (cur_offset == -1) { - begin -= CHUNKSIZE; - if (begin < 0) - begin = 0; - - /* seek CHUNKSIZE back */ - gst_ogg_demux_seek (ogg, begin); - - /* now continue reading until we run out of data, if we find a page - * start, we save it. It might not be the final page as there could be - * another page after this one. */ - while (ogg->offset < end) { - gint64 new_offset; - - ret = - gst_ogg_demux_get_next_page (ogg, og, end - ogg->offset, &new_offset); - /* we hit the upper limit, offset contains the last page start */ - if (ret == GST_FLOW_LIMIT) - break; - /* something went wrong */ - if (ret == GST_FLOW_UNEXPECTED) - new_offset = 0; - else if (ret != GST_FLOW_OK) - return ret; - - /* offset is next page start */ - cur_offset = new_offset; - } - } - - /* we have the offset. Actually snork and hold the page now */ - gst_ogg_demux_seek (ogg, cur_offset); - ret = gst_ogg_demux_get_next_page (ogg, og, -1, NULL); - if (ret != GST_FLOW_OK) - /* this shouldn't be possible */ - return ret; - - if (offset) - *offset = cur_offset; - - return ret; -} - -static gboolean -gst_ogg_demux_deactivate_current_chain (GstOggDemux * ogg) -{ - gint i; - GstOggChain *chain = ogg->current_chain; - - if (chain == NULL) - return TRUE; - - GST_DEBUG_OBJECT (ogg, "deactivating chain %p", chain); - - /* send EOS on all the pads */ - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - - gst_pad_push_event (GST_PAD_CAST (pad), gst_event_new_eos ()); - - GST_DEBUG_OBJECT (ogg, "removing pad %" GST_PTR_FORMAT, pad); - - /* deactivate first */ - gst_pad_set_active (GST_PAD_CAST (pad), FALSE); - - gst_element_remove_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad)); - } - /* if we cannot seek back to the chain, we can destroy the chain - * completely */ - if (!ogg->seekable) { - gst_ogg_chain_free (chain); - } - ogg->current_chain = NULL; - - return TRUE; -} - -static gboolean -gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain, - GstEvent * event) -{ - gint i; - - if (chain == ogg->current_chain) { - if (event) - gst_event_unref (event); - return TRUE; - } - - gst_ogg_demux_deactivate_current_chain (ogg); - - /* FIXME, should not be called with NULL */ - if (chain == NULL) { - ogg->current_chain = chain; - return TRUE; - } - - GST_DEBUG_OBJECT (ogg, "activating chain %p", chain); - - /* first add the pads */ - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad; - - pad = g_array_index (chain->streams, GstOggPad *, i); - GST_DEBUG_OBJECT (ogg, "adding pad %" GST_PTR_FORMAT, pad); - - /* mark discont */ - pad->discont = TRUE; - pad->last_ret = GST_FLOW_OK; - - /* activate first */ - gst_pad_set_active (GST_PAD_CAST (pad), TRUE); - - gst_element_add_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad)); - } - - gst_element_no_more_pads (GST_ELEMENT (ogg)); - ogg->current_chain = chain; - - /* FIXME, must be sent from the streaming thread */ - if (event) - gst_ogg_demux_send_event (ogg, event); - - GST_DEBUG_OBJECT (ogg, "starting chain"); - - /* then send out any queued buffers */ - for (i = 0; i < chain->streams->len; i++) { - GList *headers; - GstOggPad *pad; - - pad = g_array_index (chain->streams, GstOggPad *, i); - - for (headers = pad->headers; headers; headers = g_list_next (headers)) { - GstBuffer *buffer = GST_BUFFER (headers->data); - - if (pad->discont) { - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); - pad->discont = FALSE; - } - - /* we don't care about the return value here */ - gst_pad_push (GST_PAD_CAST (pad), buffer); - } - /* and free the headers */ - g_list_free (pad->headers); - pad->headers = NULL; - } - return TRUE; -} - -/* - * do seek to time @position, return FALSE or chain and TRUE - */ -static gboolean -gst_ogg_demux_do_seek (GstOggDemux * ogg, gint64 position, gboolean accurate, - GstOggChain ** rchain) -{ - GstOggChain *chain = NULL; - gint64 begin, end; - gint64 begintime, endtime; - gint64 target; - gint64 best; - gint64 total; - gint64 result = 0; - GstFlowReturn ret; - gint i; - - /* first find the chain to search in */ - total = ogg->total_time; - if (ogg->chains->len == 0) - goto no_chains; - - for (i = ogg->chains->len - 1; i >= 0; i--) { - chain = g_array_index (ogg->chains, GstOggChain *, i); - total -= chain->total_time; - if (position >= total) - break; - } - - begin = chain->offset; - end = chain->end_offset; - begintime = chain->begin_time; - endtime = chain->begin_time + chain->total_time; - target = position - total + begintime; - if (accurate) { - /* FIXME, seek 4 seconds early to catch keyframes, better implement - * keyframe detection. */ - target = target - (gint64) 4 *GST_SECOND; - } - target = MAX (target, 0); - best = begin; - - GST_DEBUG_OBJECT (ogg, - "seeking to %" GST_TIME_FORMAT " in chain %p", - GST_TIME_ARGS (position), chain); - GST_DEBUG_OBJECT (ogg, - "chain offset %" G_GINT64_FORMAT ", end offset %" G_GINT64_FORMAT, begin, - end); - GST_DEBUG_OBJECT (ogg, - "chain begin time %" GST_TIME_FORMAT ", end time %" GST_TIME_FORMAT, - GST_TIME_ARGS (begintime), GST_TIME_ARGS (endtime)); - GST_DEBUG_OBJECT (ogg, "target %" GST_TIME_FORMAT, GST_TIME_ARGS (target)); - - /* perform the seek */ - while (begin < end) { - gint64 bisect; - - if ((end - begin < CHUNKSIZE) || (endtime == begintime)) { - bisect = begin; - } else { - /* take a (pretty decent) guess, avoiding overflow */ - gint64 rate = (end - begin) * GST_MSECOND / (endtime - begintime); - - bisect = (target - begintime) / GST_MSECOND * rate + begin - CHUNKSIZE; - - if (bisect <= begin) - bisect = begin; - GST_DEBUG_OBJECT (ogg, "Initial guess: %" G_GINT64_FORMAT, bisect); - } - gst_ogg_demux_seek (ogg, bisect); - - while (begin < end) { - ogg_page og; - - GST_DEBUG_OBJECT (ogg, - "after seek, bisect %" G_GINT64_FORMAT ", begin %" G_GINT64_FORMAT - ", end %" G_GINT64_FORMAT, bisect, begin, end); - - ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, &result); - GST_LOG_OBJECT (ogg, "looking for next page returned %" G_GINT64_FORMAT, - result); - - if (ret == GST_FLOW_LIMIT) { - /* we hit the upper limit, go back a bit */ - if (bisect <= begin + 1) { - end = begin; /* found it */ - } else { - if (bisect == 0) - goto seek_error; - - bisect -= CHUNKSIZE; - if (bisect <= begin) - bisect = begin + 1; - - gst_ogg_demux_seek (ogg, bisect); - } - } else if (ret == GST_FLOW_OK) { - /* found offset of next ogg page */ - gint64 granulepos; - GstClockTime granuletime; - GstFormat format; - GstOggPad *pad; - - GST_LOG_OBJECT (ogg, "found next ogg page at %" G_GINT64_FORMAT, - result); - granulepos = ogg_page_granulepos (&og); - if (granulepos == -1) { - GST_LOG_OBJECT (ogg, "granulepos of next page is -1"); - continue; - } - - pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og)); - if (pad == NULL || pad->is_skeleton) - continue; - - format = GST_FORMAT_TIME; - if (!gst_ogg_pad_query_convert (pad, - GST_FORMAT_DEFAULT, granulepos, &format, - (gint64 *) & granuletime)) { - GST_WARNING_OBJECT (ogg, "could not convert granulepos to time"); - granuletime = target; - } else { - if (granuletime < pad->start_time) - continue; - GST_LOG_OBJECT (ogg, "granulepos %" G_GINT64_FORMAT " maps to time %" - GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (granuletime)); - - granuletime -= pad->start_time; - } - - GST_DEBUG_OBJECT (ogg, - "found page with granule %" G_GINT64_FORMAT " and time %" - GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (granuletime)); - - if (granuletime < target) { - best = result; /* raw offset of packet with granulepos */ - begin = ogg->offset; /* raw offset of next page */ - begintime = granuletime; - - if (target - begintime > GST_SECOND) - break; - - bisect = begin; /* *not* begin + 1 */ - } else { - if (bisect <= begin + 1) { - end = begin; /* found it */ - } else { - if (end == ogg->offset) { /* we're pretty close - we'd be stuck in */ - end = result; - bisect -= CHUNKSIZE; /* an endless loop otherwise. */ - if (bisect <= begin) - bisect = begin + 1; - gst_ogg_demux_seek (ogg, bisect); - } else { - end = result; - endtime = granuletime; - break; - } - } - } - } else - goto seek_error; - } - } - - ogg->offset = best; - *rchain = chain; - - return TRUE; - -no_chains: - { - GST_DEBUG_OBJECT (ogg, "no chains"); - return FALSE; - } -seek_error: - { - GST_DEBUG_OBJECT (ogg, "got a seek error"); - return FALSE; - } -} - -/* does not take ownership of the event */ -static gboolean -gst_ogg_demux_perform_seek (GstOggDemux * ogg, GstEvent * event) -{ - GstOggChain *chain = NULL; - gboolean res; - gboolean flush, accurate; - GstFormat format; - gdouble rate; - GstSeekFlags flags; - GstSeekType cur_type, stop_type; - gint64 cur, stop; - gboolean update; - - if (event) { - GST_DEBUG_OBJECT (ogg, "seek with event"); - - gst_event_parse_seek (event, &rate, &format, &flags, - &cur_type, &cur, &stop_type, &stop); - - /* we can only seek on time */ - if (format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (ogg, "can only seek on TIME"); - goto error; - } - } else { - GST_DEBUG_OBJECT (ogg, "seek without event"); - - flags = 0; - rate = 1.0; - } - - GST_DEBUG_OBJECT (ogg, "seek, rate %g", rate); - - flush = flags & GST_SEEK_FLAG_FLUSH; - accurate = flags & GST_SEEK_FLAG_ACCURATE; - - /* first step is to unlock the streaming thread if it is - * blocked in a chain call, we do this by starting the flush. because - * we cannot yet hold any streaming lock, we have to protect the chains - * with their own lock. */ - if (flush) { - gint i; - - gst_pad_push_event (ogg->sinkpad, gst_event_new_flush_start ()); - - GST_CHAIN_LOCK (ogg); - for (i = 0; i < ogg->chains->len; i++) { - GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); - gint j; - - for (j = 0; j < chain->streams->len; j++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j); - - gst_pad_push_event (GST_PAD (pad), gst_event_new_flush_start ()); - } - } - GST_CHAIN_UNLOCK (ogg); - } else { - gst_pad_pause_task (ogg->sinkpad); - } - - /* now grab the stream lock so that streaming cannot continue, for - * non flushing seeks when the element is in PAUSED this could block - * forever. */ - GST_PAD_STREAM_LOCK (ogg->sinkpad); - - if (ogg->segment_running && !flush) { - /* create the segment event to close the current segment */ - if ((chain = ogg->current_chain)) { - GstEvent *newseg; - - newseg = gst_event_new_new_segment (TRUE, ogg->segment.rate, - GST_FORMAT_TIME, ogg->segment.start + chain->segment_start, - ogg->segment.last_stop + chain->segment_start, ogg->segment.time); - - /* send segment on old chain, FIXME, must be sent from streaming thread. */ - gst_ogg_demux_send_event (ogg, newseg); - } - } - - if (event) { - gst_segment_set_seek (&ogg->segment, rate, format, flags, - cur_type, cur, stop_type, stop, &update); - } - - GST_DEBUG_OBJECT (ogg, "segment positions set to %" GST_TIME_FORMAT "-%" - GST_TIME_FORMAT, GST_TIME_ARGS (ogg->segment.start), - GST_TIME_ARGS (ogg->segment.stop)); - - /* we need to stop flushing on the srcpad as we're going to use it - * next. We can do this as we have the STREAM lock now. */ - gst_pad_push_event (ogg->sinkpad, gst_event_new_flush_stop ()); - - { - gint i; - - /* reset all ogg streams now, need to do this from within the lock to - * make sure the streaming thread is not messing with the stream */ - for (i = 0; i < ogg->chains->len; i++) { - GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); - - gst_ogg_chain_reset (chain); - } - } - - res = gst_ogg_demux_do_seek (ogg, ogg->segment.last_stop, accurate, &chain); - - /* seek failed, make sure we continue the current chain */ - if (!res) { - chain = ogg->current_chain; - } - - if (!chain) - goto no_chain; - - /* now we have a new position, prepare for streaming again */ - { - GstEvent *event; - gint64 stop; - gint64 start; - gint64 last_stop, begin_time; - - /* we have to send the flush to the old chain, not the new one */ - if (flush) - gst_ogg_demux_send_event (ogg, gst_event_new_flush_stop ()); - - /* we need this to see how far inside the chain we need to start */ - if (chain->begin_time != GST_CLOCK_TIME_NONE) - begin_time = chain->begin_time; - else - begin_time = 0; - - /* segment.start gives the start over all chains, we calculate the amount - * of time into this chain we need to start */ - start = ogg->segment.start - begin_time; - if (chain->segment_start != GST_CLOCK_TIME_NONE) - start += chain->segment_start; - - if ((stop = ogg->segment.stop) == -1) - stop = ogg->segment.duration; - - /* segment.stop gives the stop time over all chains, calculate the amount of - * time we need to stop in this chain */ - if (stop != -1) { - if (stop > begin_time) - stop -= begin_time; - else - stop = 0; - stop += chain->segment_start; - /* we must stop when this chain ends and switch to the next chain to play - * the remainder of the segment. */ - stop = MIN (stop, chain->segment_stop); - } - - last_stop = ogg->segment.last_stop - begin_time; - if (chain->segment_start != GST_CLOCK_TIME_NONE) - last_stop += chain->segment_start; - - /* create the segment event we are going to send out */ - if (ogg->segment.rate >= 0.0) - event = gst_event_new_new_segment (FALSE, ogg->segment.rate, - ogg->segment.format, last_stop, stop, ogg->segment.time); - else - event = gst_event_new_new_segment (FALSE, ogg->segment.rate, - ogg->segment.format, start, last_stop, ogg->segment.time); - - if (chain != ogg->current_chain) { - /* switch to different chain, send segment on new chain */ - gst_ogg_demux_activate_chain (ogg, chain, event); - } else { - /* mark discont and send segment on current chain */ - gst_ogg_chain_mark_discont (chain); - /* This event should be sent from the streaming thread (sink pad task) */ - if (ogg->newsegment) - gst_event_unref (ogg->newsegment); - ogg->newsegment = event; - } - - /* notify start of new segment */ - if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) { - gst_element_post_message (GST_ELEMENT (ogg), - gst_message_new_segment_start (GST_OBJECT (ogg), - GST_FORMAT_TIME, ogg->segment.last_stop)); - } - - ogg->segment_running = TRUE; - /* restart our task since it might have been stopped when we did the - * flush. */ - gst_pad_start_task (ogg->sinkpad, (GstTaskFunction) gst_ogg_demux_loop, - ogg->sinkpad); - } - - /* streaming can continue now */ - GST_PAD_STREAM_UNLOCK (ogg->sinkpad); - - return res; - -error: - { - GST_DEBUG_OBJECT (ogg, "seek failed"); - return FALSE; - } -no_chain: - { - GST_DEBUG_OBJECT (ogg, "no chain to seek in"); - GST_PAD_STREAM_UNLOCK (ogg->sinkpad); - return FALSE; - } -} - -/* finds each bitstream link one at a time using a bisection search - * (has to begin by knowing the offset of the lb's initial page). - * Recurses for each link so it can alloc the link storage after - * finding them all, then unroll and fill the cache at the same time - */ -static GstFlowReturn -gst_ogg_demux_bisect_forward_serialno (GstOggDemux * ogg, - gint64 begin, gint64 searched, gint64 end, GstOggChain * chain, glong m) -{ - gint64 endsearched = end; - gint64 next = end; - ogg_page og; - GstFlowReturn ret; - gint64 offset; - GstOggChain *nextchain; - - GST_LOG_OBJECT (ogg, - "bisect begin: %" G_GINT64_FORMAT ", searched: %" G_GINT64_FORMAT - ", end %" G_GINT64_FORMAT ", chain: %p", begin, searched, end, chain); - - /* the below guards against garbage seperating the last and - * first pages of two links. */ - while (searched < endsearched) { - gint64 bisect; - - if (endsearched - searched < CHUNKSIZE) { - bisect = searched; - } else { - bisect = (searched + endsearched) / 2; - } - - gst_ogg_demux_seek (ogg, bisect); - ret = gst_ogg_demux_get_next_page (ogg, &og, -1, &offset); - - if (ret == GST_FLOW_UNEXPECTED) { - endsearched = bisect; - } else if (ret == GST_FLOW_OK) { - glong serial = ogg_page_serialno (&og); - - if (!gst_ogg_chain_has_stream (chain, serial)) { - endsearched = bisect; - next = offset; - } else { - searched = offset + og.header_len + og.body_len; - } - } else - return ret; - } - - GST_LOG_OBJECT (ogg, "current chain ends at %" G_GINT64_FORMAT, searched); - - chain->end_offset = searched; - ret = gst_ogg_demux_read_end_chain (ogg, chain); - if (ret != GST_FLOW_OK) - return ret; - - GST_LOG_OBJECT (ogg, "found begin at %" G_GINT64_FORMAT, next); - - gst_ogg_demux_seek (ogg, next); - ret = gst_ogg_demux_read_chain (ogg, &nextchain); - if (ret == GST_FLOW_UNEXPECTED) { - nextchain = NULL; - ret = GST_FLOW_OK; - GST_LOG_OBJECT (ogg, "no next chain"); - } else if (ret != GST_FLOW_OK) - goto done; - - if (searched < end && nextchain != NULL) { - ret = gst_ogg_demux_bisect_forward_serialno (ogg, next, ogg->offset, - end, nextchain, m + 1); - if (ret != GST_FLOW_OK) - goto done; - } - GST_LOG_OBJECT (ogg, "adding chain %p", chain); - - g_array_insert_val (ogg->chains, 0, chain); - -done: - return ret; -} - -/* read a chain from the ogg file. This code will - * read all BOS pages and will create and return a GstOggChain - * structure with the results. - * - * This function will also read N pages from each stream in the - * chain and submit them to the decoders. When the decoder has - * decoded the first buffer, we know the timestamp of the first - * page in the chain. - */ -static GstFlowReturn -gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain) -{ - GstFlowReturn ret; - GstOggChain *chain = NULL; - gint64 offset = ogg->offset; - ogg_page op; - gboolean done; - gint i; - - GST_LOG_OBJECT (ogg, "reading chain at %" G_GINT64_FORMAT, offset); - - /* first read the BOS pages, do typefind on them, create - * the decoders, send data to the decoders. */ - while (TRUE) { - GstOggPad *pad; - glong serial; - - ret = gst_ogg_demux_get_next_page (ogg, &op, -1, NULL); - if (ret != GST_FLOW_OK) { - GST_WARNING_OBJECT (ogg, "problem reading BOS page: ret=%d", ret); - break; - } - if (!ogg_page_bos (&op)) { - GST_WARNING_OBJECT (ogg, "page is not BOS page"); - break; - } - - if (chain == NULL) { - chain = gst_ogg_chain_new (ogg); - chain->offset = offset; - } - - serial = ogg_page_serialno (&op); - if (gst_ogg_chain_get_stream (chain, serial) != NULL) { - GST_WARNING_OBJECT (ogg, "found serial %08lx BOS page twice, ignoring", - serial); - continue; - } - - pad = gst_ogg_chain_new_stream (chain, serial); - gst_ogg_pad_submit_page (pad, &op); - } - - if (ret != GST_FLOW_OK || chain == NULL) { - if (ret != GST_FLOW_UNEXPECTED) { - GST_WARNING_OBJECT (ogg, "failed to read chain"); - } else { - GST_DEBUG_OBJECT (ogg, "done reading chains"); - } - if (chain) { - gst_ogg_chain_free (chain); - } - if (res_chain) - *res_chain = NULL; - return ret; - } - - chain->have_bos = TRUE; - GST_LOG_OBJECT (ogg, "read bos pages, init decoder now"); - - /* now read pages until we receive a buffer from each of the - * stream decoders, this will tell us the timestamp of the - * first packet in the chain then */ - - /* save the offset to the first non bos page in the chain: if searching for - * pad->first_time we read past the end of the chain, we'll seek back to this - * position - */ - offset = ogg->offset; - - done = FALSE; - while (!done) { - glong serial; - gboolean known_serial = FALSE; - GstFlowReturn ret; - - serial = ogg_page_serialno (&op); - done = TRUE; - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - - GST_LOG_OBJECT (ogg, "serial %08x time %" GST_TIME_FORMAT, pad->serialno, - GST_TIME_ARGS (pad->start_time)); - - if (pad->serialno == serial) { - known_serial = TRUE; - - /* submit the page now, this will fill in the start_time when the - * internal decoder finds it */ - gst_ogg_pad_submit_page (pad, &op); - - if (!pad->is_skeleton && pad->start_time == -1 && ogg_page_eos (&op)) { - /* got EOS on a pad before we could find its start_time. - * We have no chance of finding a start_time for every pad so - * stop searching for the other start_time(s). - */ - done = TRUE; - break; - } - } - /* the timestamp will be filled in when we submit the pages */ - if (!pad->is_skeleton) - done &= (pad->start_time != GST_CLOCK_TIME_NONE); - - GST_LOG_OBJECT (ogg, "done %08x now %d", pad->serialno, done); - } - - /* we read a page not belonging to the current chain: seek back to the - * beginning of the chain - */ - if (!known_serial) { - GST_LOG_OBJECT (ogg, "unknown serial %08lx", serial); - gst_ogg_demux_seek (ogg, offset); - break; - } - - if (!done) { - ret = gst_ogg_demux_get_next_page (ogg, &op, -1, NULL); - if (ret != GST_FLOW_OK) - break; - } - } - GST_LOG_OBJECT (ogg, "done reading chain"); - /* now we can fill in the missing info using queries */ - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - GstFormat target; - - if (pad->is_skeleton) - continue; - - GST_LOG_OBJECT (ogg, "convert first granule %" G_GUINT64_FORMAT " to time ", - pad->first_granule); - - target = GST_FORMAT_TIME; - if (!gst_ogg_pad_query_convert (pad, - GST_FORMAT_DEFAULT, pad->first_granule, &target, - (gint64 *) & pad->first_time)) { - GST_WARNING_OBJECT (ogg, "could not convert granulepos to time"); - } else { - GST_LOG_OBJECT (ogg, "converted to first time %" GST_TIME_FORMAT, - GST_TIME_ARGS (pad->first_time)); - } - - pad->mode = GST_OGG_PAD_MODE_STREAMING; - } - - if (res_chain) - *res_chain = chain; - - return GST_FLOW_OK; -} - -/* read the last pages from the ogg stream to get the final - * page end_offsets. - */ -static GstFlowReturn -gst_ogg_demux_read_end_chain (GstOggDemux * ogg, GstOggChain * chain) -{ - gint64 begin = chain->end_offset; - gint64 end = begin; - gint64 last_granule = -1; - GstOggPad *last_pad = NULL; - GstFormat target; - GstFlowReturn ret; - gboolean done = FALSE; - ogg_page og; - gint i; - - while (!done) { - begin -= CHUNKSIZE; - if (begin < 0) - begin = 0; - - gst_ogg_demux_seek (ogg, begin); - - /* now continue reading until we run out of data, if we find a page - * start, we save it. It might not be the final page as there could be - * another page after this one. */ - while (ogg->offset < end) { - ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, NULL); - - if (ret == GST_FLOW_LIMIT) - break; - if (ret != GST_FLOW_OK) - return ret; - - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - - if (pad->is_skeleton) - continue; - - if (pad->serialno == ogg_page_serialno (&og)) { - gint64 granulepos = ogg_page_granulepos (&og); - - if (last_granule < granulepos) { - last_granule = granulepos; - last_pad = pad; - } - done = TRUE; - break; - } - } - } - } - - target = GST_FORMAT_TIME; - if (last_granule == -1 || !gst_ogg_pad_query_convert (last_pad, - GST_FORMAT_DEFAULT, last_granule, &target, - (gint64 *) & chain->segment_stop)) { - GST_WARNING_OBJECT (ogg, "could not convert granulepos to time"); - chain->segment_stop = GST_CLOCK_TIME_NONE; - } - - return GST_FLOW_OK; -} - -/* find a pad with a given serial number - */ -static GstOggPad * -gst_ogg_demux_find_pad (GstOggDemux * ogg, int serialno) -{ - GstOggPad *pad; - gint i; - - /* first look in building chain if any */ - if (ogg->building_chain) { - pad = gst_ogg_chain_get_stream (ogg->building_chain, serialno); - if (pad) - return pad; - } - - /* then look in current chain if any */ - if (ogg->current_chain) { - pad = gst_ogg_chain_get_stream (ogg->current_chain, serialno); - if (pad) - return pad; - } - - for (i = 0; i < ogg->chains->len; i++) { - GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); - - pad = gst_ogg_chain_get_stream (chain, serialno); - if (pad) - return pad; - } - return NULL; -} - -/* find a chain with a given serial number - */ -static GstOggChain * -gst_ogg_demux_find_chain (GstOggDemux * ogg, int serialno) -{ - GstOggPad *pad; - - pad = gst_ogg_demux_find_pad (ogg, serialno); - if (pad) { - return pad->chain; - } - return NULL; -} - -/* returns TRUE if all streams have valid start time */ -static gboolean -gst_ogg_demux_collect_chain_info (GstOggDemux * ogg, GstOggChain * chain) -{ - gint i; - gboolean res = TRUE; - - chain->total_time = GST_CLOCK_TIME_NONE; - chain->segment_start = G_MAXUINT64; - - GST_DEBUG_OBJECT (ogg, "trying to collect chain info"); - - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - - if (pad->is_skeleton) - continue; - - /* can do this if the pad start time is not defined */ - if (pad->start_time == GST_CLOCK_TIME_NONE) - res = FALSE; - else - chain->segment_start = MIN (chain->segment_start, pad->start_time); - } - - if (chain->segment_stop != GST_CLOCK_TIME_NONE - && chain->segment_start != G_MAXUINT64) - chain->total_time = chain->segment_stop - chain->segment_start; - - GST_DEBUG_OBJECT (ogg, "return %d", res); - - return res; -} - -static void -gst_ogg_demux_collect_info (GstOggDemux * ogg) -{ - gint i; - - /* collect all info */ - ogg->total_time = 0; - - for (i = 0; i < ogg->chains->len; i++) { - GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); - - chain->begin_time = ogg->total_time; - - gst_ogg_demux_collect_chain_info (ogg, chain); - - ogg->total_time += chain->total_time; - } - gst_segment_set_duration (&ogg->segment, GST_FORMAT_TIME, ogg->total_time); -} - -/* find all the chains in the ogg file, this reads the first and - * last page of the ogg stream, if they match then the ogg file has - * just one chain, else we do a binary search for all chains. - */ -static GstFlowReturn -gst_ogg_demux_find_chains (GstOggDemux * ogg) -{ - ogg_page og; - GstPad *peer; - GstFormat format; - gboolean res; - gulong serialno; - GstOggChain *chain; - GstFlowReturn ret; - - /* get peer to figure out length */ - if ((peer = gst_pad_get_peer (ogg->sinkpad)) == NULL) - goto no_peer; - - /* find length to read last page, we store this for later use. */ - format = GST_FORMAT_BYTES; - res = gst_pad_query_duration (peer, &format, &ogg->length); - gst_object_unref (peer); - if (!res || ogg->length <= 0) - goto no_length; - - GST_DEBUG_OBJECT (ogg, "file length %" G_GINT64_FORMAT, ogg->length); - - /* read chain from offset 0, this is the first chain of the - * ogg file. */ - gst_ogg_demux_seek (ogg, 0); - ret = gst_ogg_demux_read_chain (ogg, &chain); - if (ret != GST_FLOW_OK) - goto no_first_chain; - - /* read page from end offset, we use this page to check if its serial - * number is contained in the first chain. If this is the case then - * this ogg is not a chained ogg and we can skip the scanning. */ - gst_ogg_demux_seek (ogg, ogg->length); - ret = gst_ogg_demux_get_prev_page (ogg, &og, NULL); - if (ret != GST_FLOW_OK) - goto no_last_page; - - serialno = ogg_page_serialno (&og); - - if (!gst_ogg_chain_has_stream (chain, serialno)) { - /* the last page is not in the first stream, this means we should - * find all the chains in this chained ogg. */ - ret = - gst_ogg_demux_bisect_forward_serialno (ogg, 0, 0, ogg->length, chain, - 0); - } else { - /* we still call this function here but with an empty range so that - * we can reuse the setup code in this routine. */ - ret = - gst_ogg_demux_bisect_forward_serialno (ogg, 0, ogg->length, ogg->length, - chain, 0); - } - if (ret != GST_FLOW_OK) - goto done; - - /* all fine, collect and print */ - gst_ogg_demux_collect_info (ogg); - - /* dump our chains and streams */ - gst_ogg_print (ogg); - -done: - return ret; - - /*** error cases ***/ -no_peer: - { - GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("we don't have a peer")); - return GST_FLOW_NOT_LINKED; - } -no_length: - { - GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("can't get file length")); - return GST_FLOW_NOT_SUPPORTED; - } -no_first_chain: - { - GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("can't get first chain")); - return GST_FLOW_ERROR; - } -no_last_page: - { - GST_DEBUG_OBJECT (ogg, "can't get last page"); - if (chain) - gst_ogg_chain_free (chain); - return ret; - } -} - -static GstFlowReturn -gst_ogg_demux_handle_page (GstOggDemux * ogg, ogg_page * page) -{ - GstOggPad *pad; - gint64 granule; - guint serialno; - GstFlowReturn result = GST_FLOW_OK; - - serialno = ogg_page_serialno (page); - granule = ogg_page_granulepos (page); - - GST_LOG_OBJECT (ogg, - "processing ogg page (serial %08x, pageno %ld, granulepos %" - G_GINT64_FORMAT ", bos %d)", - serialno, ogg_page_pageno (page), granule, ogg_page_bos (page)); - - if (ogg_page_bos (page)) { - GstOggChain *chain; - - /* first page */ - /* see if we know about the chain already */ - chain = gst_ogg_demux_find_chain (ogg, serialno); - if (chain) { - GstEvent *event; - - /* create the newsegment event we are going to send out */ - event = gst_event_new_new_segment (FALSE, ogg->segment.rate, - GST_FORMAT_TIME, chain->segment_start, chain->segment_stop, - chain->begin_time); - - GST_DEBUG_OBJECT (ogg, - "segment: start %" GST_TIME_FORMAT ", stop %" GST_TIME_FORMAT - ", time %" GST_TIME_FORMAT, GST_TIME_ARGS (chain->segment_start), - GST_TIME_ARGS (chain->segment_stop), - GST_TIME_ARGS (chain->begin_time)); - - /* activate it as it means we have a non-header */ - gst_ogg_demux_activate_chain (ogg, chain, event); - pad = gst_ogg_demux_find_pad (ogg, serialno); - } else { - GstClockTime chain_time; - GstOggChain *current_chain; - gint64 current_time; - - /* this can only happen in non-seekabe mode */ - if (ogg->seekable) - goto unknown_chain; - - current_chain = ogg->current_chain; - current_time = ogg->segment.last_stop; - - if (current_chain) { - /* remove existing pads */ - gst_ogg_demux_deactivate_current_chain (ogg); - } - /* time of new chain is current time */ - chain_time = current_time; - - if (ogg->building_chain == NULL) { - GstOggChain *newchain; - - newchain = gst_ogg_chain_new (ogg); - newchain->offset = 0; - /* set new chain begin time aligned with end time of old chain */ - newchain->begin_time = chain_time; - GST_DEBUG_OBJECT (ogg, "new chain, begin time %" GST_TIME_FORMAT, - GST_TIME_ARGS (chain_time)); - - /* and this is the one we are building now */ - ogg->building_chain = newchain; - } - pad = gst_ogg_chain_new_stream (ogg->building_chain, serialno); - } - } else { - pad = gst_ogg_demux_find_pad (ogg, serialno); - } - if (pad) { - result = gst_ogg_pad_submit_page (pad, page); - } else { - /* no pad, this is pretty fatal. This means an ogg page without bos - * has been seen for this serialno. could just ignore it too... */ - goto unknown_pad; - } - return result; - - /* ERRORS */ -unknown_chain: - { - GST_ELEMENT_ERROR (ogg, STREAM, DECODE, - (NULL), ("unknown ogg chain for serial %08x detected", serialno)); - return GST_FLOW_ERROR; - } -unknown_pad: - { - GST_ELEMENT_ERROR (ogg, STREAM, DECODE, - (NULL), ("unknown ogg pad for serial %08x detected", serialno)); - return GST_FLOW_ERROR; - } -} - -/* streaming mode, receive a buffer, parse it, create pads for - * the serialno, submit pages and packets to the oggpads - */ -static GstFlowReturn -gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer) -{ - GstOggDemux *ogg; - gint ret; - GstFlowReturn result = GST_FLOW_OK; - - ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad)); - - GST_DEBUG_OBJECT (ogg, "chain"); - result = gst_ogg_demux_submit_buffer (ogg, buffer); - - while (result == GST_FLOW_OK) { - ogg_page page; - - ret = ogg_sync_pageout (&ogg->sync, &page); - if (ret == 0) - /* need more data */ - break; - if (ret == -1) { - /* discontinuity in the pages */ - GST_DEBUG_OBJECT (ogg, "discont in page found, continuing"); - } else { - result = gst_ogg_demux_handle_page (ogg, &page); - } - } - return result; -} - -static void -gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event) -{ - GstOggChain *chain = ogg->current_chain; - - if (chain) { - gint i; - - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - - gst_event_ref (event); - GST_DEBUG_OBJECT (ogg, "Pushing event on pad %p", pad); - gst_pad_push_event (GST_PAD (pad), event); - } - } - gst_event_unref (event); -} - -static GstFlowReturn -gst_ogg_demux_combine_flows (GstOggDemux * ogg, GstOggPad * pad, - GstFlowReturn ret) -{ - GstOggChain *chain; - - /* store the value */ - pad->last_ret = ret; - - /* any other error that is not-linked can be returned right - * away */ - if (ret != GST_FLOW_NOT_LINKED) - goto done; - - /* only return NOT_LINKED if all other pads returned NOT_LINKED */ - chain = ogg->current_chain; - if (chain) { - gint i; - - for (i = 0; i < chain->streams->len; i++) { - GstOggPad *opad = g_array_index (chain->streams, GstOggPad *, i); - - ret = opad->last_ret; - /* some other return value (must be SUCCESS but we can return - * other values as well) */ - if (ret != GST_FLOW_NOT_LINKED) - goto done; - } - /* if we get here, all other pads were unlinked and we return - * NOT_LINKED then */ - } -done: - return ret; -} - -static GstFlowReturn -gst_ogg_demux_loop_forward (GstOggDemux * ogg) -{ - GstFlowReturn ret; - GstBuffer *buffer; - - if (ogg->offset == ogg->length) { - GST_LOG_OBJECT (ogg, "no more data to pull %" G_GINT64_FORMAT - " == %" G_GINT64_FORMAT, ogg->offset, ogg->length); - ret = GST_FLOW_UNEXPECTED; - goto done; - } - - GST_LOG_OBJECT (ogg, "pull data %" G_GINT64_FORMAT, ogg->offset); - ret = gst_pad_pull_range (ogg->sinkpad, ogg->offset, CHUNKSIZE, &buffer); - if (ret != GST_FLOW_OK) { - GST_LOG_OBJECT (ogg, "Failed pull_range"); - goto done; - } - - ogg->offset += GST_BUFFER_SIZE (buffer); - - if (G_UNLIKELY (ogg->newsegment)) { - gst_ogg_demux_send_event (ogg, ogg->newsegment); - ogg->newsegment = NULL; - } - - ret = gst_ogg_demux_chain (ogg->sinkpad, buffer); - if (ret != GST_FLOW_OK) { - GST_LOG_OBJECT (ogg, "Failed demux_chain"); - goto done; - } - - /* check for the end of the segment */ - if (ogg->segment.stop != -1 && ogg->segment.last_stop != -1) { - if (ogg->segment.last_stop > ogg->segment.stop) { - ret = GST_FLOW_UNEXPECTED; - goto done; - } - } -done: - return ret; -} - -/* reverse mode. - * - * We read the pages backwards and send the packets forwards. The first packet - * in the page will be pushed with the DISCONT flag set. - * - * Special care has to be taken for continued pages, which we can only decode - * when we have the previous page(s). - */ -static GstFlowReturn -gst_ogg_demux_loop_reverse (GstOggDemux * ogg) -{ - GstFlowReturn ret; - ogg_page page; - gint64 offset; - - if (ogg->offset == 0) { - GST_LOG_OBJECT (ogg, "no more data to pull %" G_GINT64_FORMAT - " == 0", ogg->offset); - ret = GST_FLOW_UNEXPECTED; - goto done; - } - - GST_LOG_OBJECT (ogg, "read page from %" G_GINT64_FORMAT, ogg->offset); - ret = gst_ogg_demux_get_prev_page (ogg, &page, &offset); - if (ret != GST_FLOW_OK) - goto done; - - ogg->offset = offset; - - if (G_UNLIKELY (ogg->newsegment)) { - gst_ogg_demux_send_event (ogg, ogg->newsegment); - ogg->newsegment = NULL; - } - - ret = gst_ogg_demux_handle_page (ogg, &page); - if (ret != GST_FLOW_OK) - goto done; - - /* check for the end of the segment */ - if (ogg->segment.start != -1 && ogg->segment.last_stop != -1) { - if (ogg->segment.last_stop <= ogg->segment.start) { - ret = GST_FLOW_UNEXPECTED; - goto done; - } - } -done: - return ret; -} - -/* random access code - * - * - first find all the chains and streams by scanning the file. - * - then get and chain buffers, just like the streaming case. - * - when seeking, we can use the chain info to perform the seek. - */ -static void -gst_ogg_demux_loop (GstOggPad * pad) -{ - GstOggDemux *ogg; - GstFlowReturn ret; - GstEvent *event; - - ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad)); - - if (ogg->need_chains) { - gboolean res; - - /* this is the only place where we write chains and thus need to lock. */ - GST_CHAIN_LOCK (ogg); - ret = gst_ogg_demux_find_chains (ogg); - GST_CHAIN_UNLOCK (ogg); - if (ret != GST_FLOW_OK) - goto chain_read_failed; - - ogg->need_chains = FALSE; - - GST_OBJECT_LOCK (ogg); - ogg->running = TRUE; - event = ogg->event; - ogg->event = NULL; - GST_OBJECT_UNLOCK (ogg); - - /* and seek to configured positions without FLUSH */ - res = gst_ogg_demux_perform_seek (ogg, event); - if (event) - gst_event_unref (event); - - if (!res) - goto seek_failed; - } - - if (ogg->segment.rate >= 0.0) - ret = gst_ogg_demux_loop_forward (ogg); - else - ret = gst_ogg_demux_loop_reverse (ogg); - - if (ret != GST_FLOW_OK) - goto pause; - - return; - - /* ERRORS */ -chain_read_failed: - { - /* error was posted */ - goto pause; - } -seek_failed: - { - GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), - ("failed to start demuxing ogg")); - ret = GST_FLOW_ERROR; - goto pause; - } -pause: - { - const gchar *reason = gst_flow_get_name (ret); - - GST_LOG_OBJECT (ogg, "pausing task, reason %s", reason); - ogg->segment_running = FALSE; - gst_pad_pause_task (ogg->sinkpad); - - if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) { - if (ret == GST_FLOW_UNEXPECTED) { - /* perform EOS logic */ - if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) { - gint64 stop; - - /* for segment playback we need to post when (in stream time) - * we stopped, this is either stop (when set) or the duration. */ - if ((stop = ogg->segment.stop) == -1) - stop = ogg->segment.duration; - - GST_LOG_OBJECT (ogg, "Sending segment done, at end of segment"); - gst_element_post_message (GST_ELEMENT (ogg), - gst_message_new_segment_done (GST_OBJECT (ogg), GST_FORMAT_TIME, - stop)); - } else { - /* normal playback, send EOS to all linked pads */ - GST_LOG_OBJECT (ogg, "Sending EOS, at end of stream"); - gst_ogg_demux_send_event (ogg, gst_event_new_eos ()); - } - } else { - GST_ELEMENT_ERROR (ogg, STREAM, FAILED, - (_("Internal data stream error.")), - ("stream stopped, reason %s", reason)); - gst_ogg_demux_send_event (ogg, gst_event_new_eos ()); - } - } - return; - } -} - -static void -gst_ogg_demux_clear_chains (GstOggDemux * ogg) -{ - gint i; - - gst_ogg_demux_deactivate_current_chain (ogg); - - GST_CHAIN_LOCK (ogg); - for (i = 0; i < ogg->chains->len; i++) { - GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); - - gst_ogg_chain_free (chain); - } - ogg->chains = g_array_set_size (ogg->chains, 0); - GST_CHAIN_UNLOCK (ogg); -} - -/* this function is called when the pad is activated and should start - * processing data. - * - * We check if we can do random access to decide if we work push or - * pull based. - */ -static gboolean -gst_ogg_demux_sink_activate (GstPad * sinkpad) -{ - if (gst_pad_check_pull_range (sinkpad)) { - GST_DEBUG_OBJECT (sinkpad, "activating pull"); - return gst_pad_activate_pull (sinkpad, TRUE); - } else { - GST_DEBUG_OBJECT (sinkpad, "activating push"); - return gst_pad_activate_push (sinkpad, TRUE); - } -} - -/* this function gets called when we activate ourselves in push mode. - * We cannot seek (ourselves) in the stream */ -static gboolean -gst_ogg_demux_sink_activate_push (GstPad * sinkpad, gboolean active) -{ - GstOggDemux *ogg; - - ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (sinkpad)); - - ogg->seekable = FALSE; - - return TRUE; -} - -/* this function gets called when we activate ourselves in pull mode. - * We can perform random access to the resource and we start a task - * to start reading */ -static gboolean -gst_ogg_demux_sink_activate_pull (GstPad * sinkpad, gboolean active) -{ - GstOggDemux *ogg; - - ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (sinkpad)); - - if (active) { - ogg->need_chains = TRUE; - ogg->seekable = TRUE; - - return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_ogg_demux_loop, - sinkpad); - } else { - return gst_pad_stop_task (sinkpad); - } -} - -static GstStateChangeReturn -gst_ogg_demux_change_state (GstElement * element, GstStateChange transition) -{ - GstOggDemux *ogg; - GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; - - ogg = GST_OGG_DEMUX (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - ogg->basetime = 0; - ogg->have_fishead = FALSE; - ogg_sync_init (&ogg->sync); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - ogg_sync_reset (&ogg->sync); - ogg->current_granule = -1; - ogg->running = FALSE; - ogg->segment_running = FALSE; - gst_segment_init (&ogg->segment, GST_FORMAT_TIME); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - result = parent_class->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_ogg_demux_clear_chains (ogg); - GST_OBJECT_LOCK (ogg); - ogg->running = FALSE; - ogg->segment_running = FALSE; - ogg->have_fishead = FALSE; - GST_OBJECT_UNLOCK (ogg); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - ogg_sync_clear (&ogg->sync); - break; - default: - break; - } - return result; -} - -static GstClockTime -gst_annodex_granule_to_time (gint64 granulepos, gint64 granulerate_n, - gint64 granulerate_d, guint8 granuleshift) -{ - gint64 keyindex, keyoffset; - gint64 granulerate; - GstClockTime res; - - if (granulepos == 0 || granulerate_n == 0 || granulerate_d == 0) - return 0; - - if (granuleshift != 0) { - keyindex = granulepos >> granuleshift; - keyoffset = granulepos - (keyindex << granuleshift); - granulepos = keyindex + keyoffset; - } - - /* GST_SECOND / (granulerate_n / granulerate_d) */ - granulerate = gst_util_uint64_scale (GST_SECOND, - granulerate_d, granulerate_n); - res = gst_util_uint64_scale (granulepos, granulerate, 1); - return res; -} - -gboolean -gst_ogg_demux_plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (gst_ogg_demux_debug, "oggdemux", 0, "ogg demuxer"); - GST_DEBUG_CATEGORY_INIT (gst_ogg_demux_setup_debug, "oggdemux_setup", 0, - "ogg demuxer setup stage when parsing pipeline"); - -#if ENABLE_NLS - GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE, - LOCALEDIR); - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); -#endif - - return gst_element_register (plugin, "oggdemux", GST_RANK_PRIMARY, - GST_TYPE_OGG_DEMUX); -} - -/* prints all info about the element */ -#undef GST_CAT_DEFAULT -#define GST_CAT_DEFAULT gst_ogg_demux_setup_debug - -#ifdef GST_DISABLE_GST_DEBUG - -static void -gst_ogg_print (GstOggDemux * ogg) -{ - /* NOP */ -} - -#else /* !GST_DISABLE_GST_DEBUG */ - -static void -gst_ogg_print (GstOggDemux * ogg) -{ - guint j, i; - - GST_INFO_OBJECT (ogg, "%u chains", ogg->chains->len); - GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT, - GST_TIME_ARGS (ogg->total_time)); - - for (i = 0; i < ogg->chains->len; i++) { - GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); - - GST_INFO_OBJECT (ogg, " chain %d (%u streams):", i, chain->streams->len); - GST_INFO_OBJECT (ogg, " offset: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT, - chain->offset, chain->end_offset); - GST_INFO_OBJECT (ogg, " begin time: %" GST_TIME_FORMAT, - GST_TIME_ARGS (chain->begin_time)); - GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT, - GST_TIME_ARGS (chain->total_time)); - GST_INFO_OBJECT (ogg, " segment start: %" GST_TIME_FORMAT, - GST_TIME_ARGS (chain->segment_start)); - GST_INFO_OBJECT (ogg, " segment stop: %" GST_TIME_FORMAT, - GST_TIME_ARGS (chain->segment_stop)); - - for (j = 0; j < chain->streams->len; j++) { - GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, j); - - GST_INFO_OBJECT (ogg, " stream %08x:", stream->serialno); - GST_INFO_OBJECT (ogg, " start time: %" GST_TIME_FORMAT, - GST_TIME_ARGS (stream->start_time)); - GST_INFO_OBJECT (ogg, " first granulepos: %" G_GINT64_FORMAT, - stream->first_granule); - GST_INFO_OBJECT (ogg, " first time: %" GST_TIME_FORMAT, - GST_TIME_ARGS (stream->first_time)); - } - } -} -#endif /* GST_DISABLE_GST_DEBUG */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/ogg/gstoggdemux.h --- a/gst_plugins_base/ext/ogg/gstoggdemux.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,184 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Wim Taymans - * - * gstoggdemux.c: ogg stream demuxer - * - * 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. - */ - -#ifndef __GST_OGG_DEMUX_H__ -#define __GST_OGG_DEMUX_H__ - -#include - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_OGG_PAD (gst_ogg_pad_get_type()) -#define GST_OGG_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_PAD, GstOggPad)) -#define GST_OGG_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_PAD, GstOggPad)) -#define GST_IS_OGG_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_PAD)) -#define GST_IS_OGG_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_PAD)) - -typedef struct _GstOggPad GstOggPad; -typedef struct _GstOggPadClass GstOggPadClass; - -#define GST_TYPE_OGG_DEMUX (gst_ogg_demux_get_type()) -#define GST_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_DEMUX, GstOggDemux)) -#define GST_OGG_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_DEMUX, GstOggDemux)) -#define GST_IS_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_DEMUX)) -#define GST_IS_OGG_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_DEMUX)) - -static GType gst_ogg_demux_get_type (void); - -typedef struct _GstOggDemux GstOggDemux; -typedef struct _GstOggDemuxClass GstOggDemuxClass; -typedef struct _GstOggChain GstOggChain; - -/* all information needed for one ogg chain (relevant for chained bitstreams) */ -struct _GstOggChain -{ - GstOggDemux *ogg; - - gint64 offset; /* starting offset of chain */ - gint64 end_offset; /* end offset of chain */ - gint64 bytes; /* number of bytes */ - - gboolean have_bos; - - GArray *streams; - - GstClockTime total_time; /* the total time of this chain, this is the MAX of - the totals of all streams */ - GstClockTime begin_time; /* when this chain starts in the stream */ - - GstClockTime segment_start; /* the timestamp of the first sample, this is the MIN of - the start times of all streams. */ - GstClockTime segment_stop; /* the timestamp of the last page, this is the MAX of the - streams. */ -}; - -/* different modes for the pad */ -typedef enum -{ - GST_OGG_PAD_MODE_INIT, /* we are feeding our internal decoder to get info */ - GST_OGG_PAD_MODE_STREAMING, /* we are streaming buffers to the outside */ -} GstOggPadMode; - -/* all information needed for one ogg stream */ -struct _GstOggPad -{ - GstPad pad; /* subclass GstPad */ - - gboolean have_type; - GstOggPadMode mode; - - GstPad *elem_pad; /* sinkpad of internal element */ - GstElement *element; /* internal element */ - GstPad *elem_out; /* our sinkpad to receive buffers form the internal element */ - - GstOggChain *chain; /* the chain we are part of */ - GstOggDemux *ogg; /* the ogg demuxer we are part of */ - - GList *headers; - - gboolean is_skeleton; - gboolean have_fisbone; - gint64 granulerate_n; - gint64 granulerate_d; - guint32 preroll; - guint granuleshift; - - gint serialno; - gint64 packetno; - gint64 current_granule; - - GstClockTime start_time; /* the timestamp of the first sample */ - - gint64 first_granule; /* the granulepos of first page == first sample in next page */ - GstClockTime first_time; /* the timestamp of the second page or granuletime of first page */ - - ogg_stream_state stream; - GList *continued; - - gboolean discont; - GstFlowReturn last_ret; /* last return of _pad_push() */ - - gboolean dynamic; /* True if the internal element had dynamic pads */ - guint padaddedid; /* The signal id for element::pad-added */ -}; - -struct _GstOggPadClass -{ - GstPadClass parent_class; -}; - -#define GST_CHAIN_LOCK(ogg) g_mutex_lock((ogg)->chain_lock) -#define GST_CHAIN_UNLOCK(ogg) g_mutex_unlock((ogg)->chain_lock) - -/** - * GstOggDemux: - * - * The ogg demuxer object structure. - */ -struct _GstOggDemux -{ - GstElement element; - - GstPad *sinkpad; - - gint64 length; - gint64 offset; - - gboolean seekable; - gboolean running; - - gboolean need_chains; - - /* state */ - GMutex *chain_lock; /* we need the lock to protect the chains */ - GArray *chains; /* list of chains we know */ - GstClockTime total_time; - - GstOggChain *current_chain; - GstOggChain *building_chain; - - /* playback start/stop positions */ - GstSegment segment; - gboolean segment_running; - - GstEvent *event; - GstEvent *newsegment; /* pending newsegment to be sent from _loop */ - - gint64 current_granule; - - /* annodex stuff */ - gboolean have_fishead; - gint64 basetime; - - /* ogg stuff */ - ogg_sync_state sync; -}; - -struct _GstOggDemuxClass -{ - GstElementClass parent_class; -}; - -G_END_DECLS - -#endif /* __GST_OGG_DEMUX_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/ogg/gstoggmux.c --- a/gst_plugins_base/ext/ogg/gstoggmux.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1627 +0,0 @@ -/* OGG muxer plugin for GStreamer - * Copyright (C) 2004 Wim Taymans - * Copyright (C) 2006 Thomas Vander Stichele - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include "gstoggmux.h" - -/* memcpy - if someone knows a way to get rid of it, please speak up - * note: the ogg docs even say you need this... */ -#include -#include -#include /* rand, srand, atoi */ - -GST_DEBUG_CATEGORY_STATIC (gst_ogg_mux_debug); -#define GST_CAT_DEFAULT gst_ogg_mux_debug - -/* This isn't generally what you'd want with an end-time macro, because - technically the end time of a buffer with invalid duration is invalid. But - for sorting ogg pages this is what we want. */ -#define GST_BUFFER_END_TIME(buf) \ - (GST_BUFFER_DURATION_IS_VALID (buf) \ - ? GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf) \ - : GST_BUFFER_TIMESTAMP (buf)) - -#define GST_GP_FORMAT "[gp %8" G_GINT64_FORMAT "]" - -typedef enum -{ - GST_OGG_FLAG_BOS = GST_ELEMENT_FLAG_LAST, - GST_OGG_FLAG_EOS -} -GstOggFlag; - -/* elementfactory information */ -static const GstElementDetails gst_ogg_mux_details = -GST_ELEMENT_DETAILS ("Ogg muxer", - "Codec/Muxer", - "mux ogg streams (info about ogg: http://xiph.org)", - "Wim Taymans "); - -/* OggMux signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -/* set to 0.5 seconds by default */ -#define DEFAULT_MAX_DELAY G_GINT64_CONSTANT(500000000) -#define DEFAULT_MAX_PAGE_DELAY G_GINT64_CONSTANT(500000000) -enum -{ - ARG_0, - ARG_MAX_DELAY, - ARG_MAX_PAGE_DELAY, -}; - -static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/ogg") - ); - -static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%d", - GST_PAD_SINK, - GST_PAD_REQUEST, - GST_STATIC_CAPS ("video/x-theora; " - "audio/x-vorbis; audio/x-flac; audio/x-speex; " - "application/x-ogm-video; application/x-ogm-audio; video/x-dirac; " - "video/x-smoke; text/x-cmml, encoded = (boolean) TRUE") - ); - -static void gst_ogg_mux_base_init (gpointer g_class); -static void gst_ogg_mux_class_init (GstOggMuxClass * klass); -static void gst_ogg_mux_init (GstOggMux * ogg_mux); -static void gst_ogg_mux_finalize (GObject * object); - -static GstFlowReturn -gst_ogg_mux_collected (GstCollectPads * pads, GstOggMux * ogg_mux); -static gboolean gst_ogg_mux_handle_src_event (GstPad * pad, GstEvent * event); -static GstPad *gst_ogg_mux_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * name); -static void gst_ogg_mux_release_pad (GstElement * element, GstPad * pad); - -static void gst_ogg_mux_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_ogg_mux_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); -static GstStateChangeReturn gst_ogg_mux_change_state (GstElement * element, - GstStateChange transition); - -static GstElementClass *parent_class = NULL; - -/*static guint gst_ogg_mux_signals[LAST_SIGNAL] = { 0 }; */ - -GType -gst_ogg_mux_get_type (void) -{ - static GType ogg_mux_type = 0; - - if (G_UNLIKELY (ogg_mux_type == 0)) { - static const GTypeInfo ogg_mux_info = { - sizeof (GstOggMuxClass), - gst_ogg_mux_base_init, - NULL, - (GClassInitFunc) gst_ogg_mux_class_init, - NULL, - NULL, - sizeof (GstOggMux), - 0, - (GInstanceInitFunc) gst_ogg_mux_init, - }; - - ogg_mux_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstOggMux", &ogg_mux_info, - 0); - } - return ogg_mux_type; -} - -static void -gst_ogg_mux_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_factory)); - - gst_element_class_set_details (element_class, &gst_ogg_mux_details); -} - -static void -gst_ogg_mux_class_init (GstOggMuxClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = gst_ogg_mux_finalize; - gobject_class->get_property = gst_ogg_mux_get_property; - gobject_class->set_property = gst_ogg_mux_set_property; - - gstelement_class->request_new_pad = gst_ogg_mux_request_new_pad; - gstelement_class->release_pad = gst_ogg_mux_release_pad; - - g_object_class_install_property (gobject_class, ARG_MAX_DELAY, - g_param_spec_uint64 ("max-delay", "Max delay", - "Maximum delay in multiplexing streams", 0, G_MAXUINT64, - DEFAULT_MAX_DELAY, (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_MAX_PAGE_DELAY, - g_param_spec_uint64 ("max-page-delay", "Max page delay", - "Maximum delay for sending out a page", 0, G_MAXUINT64, - DEFAULT_MAX_PAGE_DELAY, (GParamFlags) G_PARAM_READWRITE)); - - gstelement_class->change_state = gst_ogg_mux_change_state; - -} - -#if 0 -static const GstEventMask * -gst_ogg_mux_get_sink_event_masks (GstPad * pad) -{ - static const GstEventMask gst_ogg_mux_sink_event_masks[] = { - {GST_EVENT_EOS, 0}, - {GST_EVENT_DISCONTINUOUS, 0}, - {0,} - }; - - return gst_ogg_mux_sink_event_masks; -} -#endif - -static void -gst_ogg_mux_clear (GstOggMux * ogg_mux) -{ - ogg_mux->pulling = NULL; - ogg_mux->need_headers = TRUE; - ogg_mux->max_delay = DEFAULT_MAX_DELAY; - ogg_mux->max_page_delay = DEFAULT_MAX_PAGE_DELAY; - ogg_mux->delta_pad = NULL; - ogg_mux->offset = 0; - ogg_mux->next_ts = 0; - ogg_mux->last_ts = GST_CLOCK_TIME_NONE; -} - -static void -gst_ogg_mux_init (GstOggMux * ogg_mux) -{ - GstElementClass *klass = GST_ELEMENT_GET_CLASS (ogg_mux); - - ogg_mux->srcpad = - gst_pad_new_from_template (gst_element_class_get_pad_template (klass, - "src"), "src"); - gst_pad_set_event_function (ogg_mux->srcpad, gst_ogg_mux_handle_src_event); - gst_element_add_pad (GST_ELEMENT (ogg_mux), ogg_mux->srcpad); - - GST_OBJECT_FLAG_SET (GST_ELEMENT (ogg_mux), GST_OGG_FLAG_BOS); - - /* seed random number generator for creation of serial numbers */ - srand (time (NULL)); - - ogg_mux->collect = gst_collect_pads_new (); - gst_collect_pads_set_function (ogg_mux->collect, - (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_ogg_mux_collected), - ogg_mux); - - gst_ogg_mux_clear (ogg_mux); -} - -static void -gst_ogg_mux_finalize (GObject * object) -{ - GstOggMux *ogg_mux; - - ogg_mux = GST_OGG_MUX (object); - - if (ogg_mux->collect) { - gst_object_unref (ogg_mux->collect); - ogg_mux->collect = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_ogg_mux_ogg_pad_destroy_notify (GstCollectData * data) -{ - GstOggPad *oggpad = (GstOggPad *) data; - GstBuffer *buf; - - ogg_stream_clear (&oggpad->stream); - - if (oggpad->pagebuffers) { - while ((buf = g_queue_pop_head (oggpad->pagebuffers)) != NULL) { - gst_buffer_unref (buf); - } - g_queue_free (oggpad->pagebuffers); - oggpad->pagebuffers = NULL; - } -} - -static GstPadLinkReturn -gst_ogg_mux_sinkconnect (GstPad * pad, GstPad * peer) -{ - GstOggMux *ogg_mux; - - ogg_mux = GST_OGG_MUX (gst_pad_get_parent (pad)); - - GST_DEBUG_OBJECT (ogg_mux, "sinkconnect triggered on %s", GST_PAD_NAME (pad)); - - gst_object_unref (ogg_mux); - - return GST_PAD_LINK_OK; -} - -static GstPad * -gst_ogg_mux_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * req_name) -{ - GstOggMux *ogg_mux; - GstPad *newpad; - GstElementClass *klass; - - g_return_val_if_fail (templ != NULL, NULL); - - if (templ->direction != GST_PAD_SINK) - goto wrong_direction; - - g_return_val_if_fail (GST_IS_OGG_MUX (element), NULL); - ogg_mux = GST_OGG_MUX (element); - - klass = GST_ELEMENT_GET_CLASS (element); - - if (templ != gst_element_class_get_pad_template (klass, "sink_%d")) - goto wrong_template; - - { - gint serial; - gchar *name; - - if (req_name == NULL || strlen (req_name) < 6) { - /* no name given when requesting the pad, use random serial number */ - serial = rand (); - } else { - /* parse serial number from requested padname */ - serial = atoi (&req_name[5]); - } - /* create new pad with the name */ - GST_DEBUG_OBJECT (ogg_mux, "Creating new pad for serial %d", serial); - name = g_strdup_printf ("sink_%d", serial); - newpad = gst_pad_new_from_template (templ, name); - g_free (name); - - /* construct our own wrapper data structure for the pad to - * keep track of its status */ - { - GstOggPad *oggpad; - - oggpad = (GstOggPad *) - gst_collect_pads_add_pad_full (ogg_mux->collect, newpad, - sizeof (GstOggPad), gst_ogg_mux_ogg_pad_destroy_notify); - ogg_mux->active_pads++; - - oggpad->serial = serial; - ogg_stream_init (&oggpad->stream, serial); - oggpad->packetno = 0; - oggpad->pageno = 0; - oggpad->eos = FALSE; - /* we assume there will be some control data first for this pad */ - oggpad->state = GST_OGG_PAD_STATE_CONTROL; - oggpad->new_page = TRUE; - oggpad->first_delta = FALSE; - oggpad->prev_delta = FALSE; - oggpad->pagebuffers = g_queue_new (); - } - } - - /* setup some pad functions */ - gst_pad_set_link_function (newpad, gst_ogg_mux_sinkconnect); - /* dd the pad to the element */ - gst_element_add_pad (element, newpad); - - return newpad; - - /* ERRORS */ -wrong_direction: - { - g_warning ("ogg_mux: request pad that is not a SINK pad\n"); - return NULL; - } -wrong_template: - { - g_warning ("ogg_mux: this is not our template!\n"); - return NULL; - } -} - -static void -gst_ogg_mux_release_pad (GstElement * element, GstPad * pad) -{ - GstOggMux *ogg_mux; - - ogg_mux = GST_OGG_MUX (gst_pad_get_parent (pad)); - - gst_collect_pads_remove_pad (ogg_mux->collect, pad); - gst_element_remove_pad (element, pad); - - gst_object_unref (ogg_mux); -} - -/* handle events */ -static gboolean -gst_ogg_mux_handle_src_event (GstPad * pad, GstEvent * event) -{ - GstEventType type; - - type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; - - switch (type) { - case GST_EVENT_SEEK: - /* disable seeking for now */ - return FALSE; - default: - break; - } - - return gst_pad_event_default (pad, event); -} - -static GstBuffer * -gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page, gboolean delta) -{ - GstBuffer *buffer; - - /* allocate space for header and body */ - buffer = gst_buffer_new_and_alloc (page->header_len + page->body_len); - memcpy (GST_BUFFER_DATA (buffer), page->header, page->header_len); - memcpy (GST_BUFFER_DATA (buffer) + page->header_len, - page->body, page->body_len); - - /* Here we set granulepos as our OFFSET_END to give easy direct access to - * this value later. Before we push it, we reset this to OFFSET + SIZE - * (see gst_ogg_mux_push_buffer). */ - GST_BUFFER_OFFSET_END (buffer) = ogg_page_granulepos (page); - if (delta) - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); - - GST_LOG_OBJECT (mux, GST_GP_FORMAT - " created buffer %p from ogg page", ogg_page_granulepos (page), buffer); - - return buffer; -} - -static GstFlowReturn -gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer) -{ - GstCaps *caps; - - /* fix up OFFSET and OFFSET_END again */ - GST_BUFFER_OFFSET (buffer) = mux->offset; - mux->offset += GST_BUFFER_SIZE (buffer); - GST_BUFFER_OFFSET_END (buffer) = mux->offset; - - /* Ensure we have monotonically increasing timestamps in the output. */ - if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { - if (mux->last_ts != GST_CLOCK_TIME_NONE && - GST_BUFFER_TIMESTAMP (buffer) < mux->last_ts) - GST_BUFFER_TIMESTAMP (buffer) = mux->last_ts; - else - mux->last_ts = GST_BUFFER_TIMESTAMP (buffer); - } - - caps = gst_pad_get_negotiated_caps (mux->srcpad); - gst_buffer_set_caps (buffer, caps); - gst_caps_unref (caps); - - return gst_pad_push (mux->srcpad, buffer); -} - -/* if all queues have at least one page, dequeue the page with the lowest - * timestamp */ -static gboolean -gst_ogg_mux_dequeue_page (GstOggMux * mux, GstFlowReturn * flowret) -{ - GSList *walk; - GstOggPad *opad = NULL; /* "oldest" pad */ - GstClockTime oldest = GST_CLOCK_TIME_NONE; - GstBuffer *buf = NULL; - gboolean ret = FALSE; - - *flowret = GST_FLOW_OK; - - walk = mux->collect->data; - while (walk) { - GstOggPad *pad = (GstOggPad *) walk->data; - - /* We need each queue to either be at EOS, or have one or more pages - * available with a set granulepos (i.e. not -1), otherwise we don't have - * enough data yet to determine which stream needs to go next for correct - * time ordering. */ - if (pad->pagebuffers->length == 0) { - if (pad->eos) { - GST_LOG_OBJECT (pad->collect.pad, - "pad is EOS, skipping for dequeue decision"); - } else { - GST_LOG_OBJECT (pad->collect.pad, - "no pages in this queue, can't dequeue"); - return FALSE; - } - } else { - /* We then need to check for a non-negative granulepos */ - int i; - gboolean valid = FALSE; - - for (i = 0; i < pad->pagebuffers->length; i++) { - buf = g_queue_peek_nth (pad->pagebuffers, i); - /* Here we check the OFFSET_END, which is actually temporarily the - * granulepos value for this buffer */ - if (GST_BUFFER_OFFSET_END (buf) != -1) { - valid = TRUE; - break; - } - } - if (!valid) { - GST_LOG_OBJECT (pad->collect.pad, - "No page timestamps in queue, can't dequeue"); - return FALSE; - } - } - - walk = g_slist_next (walk); - } - - walk = mux->collect->data; - while (walk) { - GstOggPad *pad = (GstOggPad *) walk->data; - - /* any page with a granulepos of -1 can be pushed immediately. - * TODO: it CAN be, but it seems silly to do so? */ - buf = g_queue_peek_head (pad->pagebuffers); - while (buf && GST_BUFFER_OFFSET_END (buf) == -1) { - GST_LOG_OBJECT (pad->collect.pad, "[gp -1] pushing page"); - g_queue_pop_head (pad->pagebuffers); - *flowret = gst_ogg_mux_push_buffer (mux, buf); - buf = g_queue_peek_head (pad->pagebuffers); - ret = TRUE; - } - - if (buf) { - /* if no oldest buffer yet, take this one */ - if (oldest == GST_CLOCK_TIME_NONE) { - GST_LOG_OBJECT (mux, "no oldest yet, taking buffer %p from pad %" - GST_PTR_FORMAT " with gp time %" GST_TIME_FORMAT, - buf, pad->collect.pad, GST_TIME_ARGS (GST_BUFFER_OFFSET (buf))); - oldest = GST_BUFFER_OFFSET (buf); - opad = pad; - } else { - /* if we have an oldest, compare with this one */ - if (GST_BUFFER_OFFSET (buf) < oldest) { - GST_LOG_OBJECT (mux, "older buffer %p, taking from pad %" - GST_PTR_FORMAT " with gp time %" GST_TIME_FORMAT, - buf, pad->collect.pad, GST_TIME_ARGS (GST_BUFFER_OFFSET (buf))); - oldest = GST_BUFFER_OFFSET (buf); - opad = pad; - } - } - } - walk = g_slist_next (walk); - } - - if (oldest != GST_CLOCK_TIME_NONE) { - g_assert (opad); - buf = g_queue_pop_head (opad->pagebuffers); - GST_LOG_OBJECT (opad->collect.pad, - GST_GP_FORMAT " pushing oldest page buffer %p (granulepos time %" - GST_TIME_FORMAT ")", GST_BUFFER_OFFSET_END (buf), buf, - GST_TIME_ARGS (GST_BUFFER_OFFSET (buf))); - *flowret = gst_ogg_mux_push_buffer (mux, buf); - ret = TRUE; - } - - return ret; -} - -/* put the given ogg page on a per-pad queue, timestamping it correctly. - * after that, dequeue and push as many pages as possible. - * Caller should make sure: - * pad->timestamp was set with the timestamp of the first packet put - * on the page - * pad->timestamp_end was set with the timestamp + duration of the last packet - * put on the page - * pad->gp_time was set with the time matching the gp of the last - * packet put on the page - * - * will also reset timestamp and timestamp_end, so caller func can restart - * counting. - */ -static GstFlowReturn -gst_ogg_mux_pad_queue_page (GstOggMux * mux, GstOggPad * pad, ogg_page * page, - gboolean delta) -{ - GstFlowReturn ret; - GstBuffer *buffer = gst_ogg_mux_buffer_from_page (mux, page, delta); - - /* take the timestamp of the first packet on this page */ - GST_BUFFER_TIMESTAMP (buffer) = pad->timestamp; - GST_BUFFER_DURATION (buffer) = pad->timestamp_end - pad->timestamp; - /* take the gp time of the last completed packet on this page */ - GST_BUFFER_OFFSET (buffer) = pad->gp_time; - - /* the next page will start where the current page's end time leaves off */ - pad->timestamp = pad->timestamp_end; - - g_queue_push_tail (pad->pagebuffers, buffer); - GST_LOG_OBJECT (pad->collect.pad, GST_GP_FORMAT - " queued buffer page %p (gp time %" - GST_TIME_FORMAT ", timestamp %" GST_TIME_FORMAT - "), %d page buffers queued", ogg_page_granulepos (page), - buffer, GST_TIME_ARGS (GST_BUFFER_OFFSET (buffer)), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), - g_queue_get_length (pad->pagebuffers)); - - while (gst_ogg_mux_dequeue_page (mux, &ret)) { - if (ret != GST_FLOW_OK) - break; - } - - return ret; -} - -/* - * Given two pads, compare the buffers queued on it. - * Returns: - * 0 if they have an equal priority - * -1 if the first is better - * 1 if the second is better - * Priority decided by: a) validity, b) older timestamp, c) smaller number - * of muxed pages - */ -static gint -gst_ogg_mux_compare_pads (GstOggMux * ogg_mux, GstOggPad * first, - GstOggPad * second) -{ - guint64 firsttime, secondtime; - - /* if the first pad doesn't contain anything or is even NULL, return - * the second pad as best candidate and vice versa */ - if (first == NULL || (first->buffer == NULL && first->next_buffer == NULL)) - return 1; - if (second == NULL || (second->buffer == NULL && second->next_buffer == NULL)) - return -1; - - /* no timestamp on first buffer, it must go first */ - if (first->buffer) - firsttime = GST_BUFFER_TIMESTAMP (first->buffer); - else - firsttime = GST_BUFFER_TIMESTAMP (first->next_buffer); - if (firsttime == GST_CLOCK_TIME_NONE) - return -1; - - /* no timestamp on second buffer, it must go first */ - if (second->buffer) - secondtime = GST_BUFFER_TIMESTAMP (second->buffer); - else - secondtime = GST_BUFFER_TIMESTAMP (second->next_buffer); - if (secondtime == GST_CLOCK_TIME_NONE) - return 1; - - /* first buffer has higher timestamp, second one should go first */ - if (secondtime < firsttime) - return 1; - /* second buffer has higher timestamp, first one should go first */ - else if (secondtime > firsttime) - return -1; - else { - /* buffers with equal timestamps, prefer the pad that has the - * least number of pages muxed */ - if (second->pageno < first->pageno) - return 1; - else if (second->pageno > first->pageno) - return -1; - } - - /* same priority if all of the above failed */ - return 0; -} - -/* make sure at least one buffer is queued on all pads, two if possible - * - * if pad->buffer == NULL, pad->next_buffer != NULL, then - * we do not know if the buffer is the last or not - * if pad->buffer != NULL, pad->next_buffer != NULL, then - * pad->buffer is not the last buffer for the pad - * if pad->buffer != NULL, pad->next_buffer == NULL, then - * pad->buffer if the last buffer for the pad - * - * returns a pointer to an oggpad that holds the best buffer, or - * NULL when no pad was usable. "best" means the buffer marked - * with the lowest timestamp. If best->buffer == NULL then nothing - * should be done until more data arrives */ -static GstOggPad * -gst_ogg_mux_queue_pads (GstOggMux * ogg_mux) -{ - GstOggPad *bestpad = NULL, *still_hungry = NULL; - GSList *walk; - - /* try to make sure we have a buffer from each usable pad first */ - walk = ogg_mux->collect->data; - while (walk) { - GstOggPad *pad; - GstCollectData *data; - - data = (GstCollectData *) walk->data; - pad = (GstOggPad *) data; - - walk = g_slist_next (walk); - - GST_LOG_OBJECT (data->pad, "looking at pad for buffer"); - - /* try to get a new buffer for this pad if needed and possible */ - if (pad->buffer == NULL) { - GstBuffer *buf; - gboolean incaps; - - /* shift the buffer along if needed (it's okay if next_buffer is NULL) */ - if (pad->buffer == NULL) { - GST_LOG_OBJECT (data->pad, "shifting buffer %" GST_PTR_FORMAT, - pad->next_buffer); - pad->buffer = pad->next_buffer; - pad->next_buffer = NULL; - } - - buf = gst_collect_pads_pop (ogg_mux->collect, data); - GST_LOG_OBJECT (data->pad, "popped buffer %" GST_PTR_FORMAT, buf); - - /* On EOS we get a NULL buffer */ - if (buf != NULL) { - if (ogg_mux->delta_pad == NULL && - GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) - ogg_mux->delta_pad = pad; - - incaps = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_IN_CAPS); - /* if we need headers */ - if (pad->state == GST_OGG_PAD_STATE_CONTROL) { - /* and we have one */ - if (incaps) { - GST_DEBUG_OBJECT (ogg_mux, - "got incaps buffer in control state, ignoring"); - /* just ignore */ - gst_buffer_unref (buf); - buf = NULL; - } else { - GST_DEBUG_OBJECT (ogg_mux, - "got data buffer in control state, switching " "to data mode"); - /* this is a data buffer so switch to data state */ - pad->state = GST_OGG_PAD_STATE_DATA; - } - } - } else { - GST_DEBUG_OBJECT (data->pad, "EOS on pad"); - if (!pad->eos) { - ogg_page page; - GstFlowReturn ret; - - /* it's no longer active */ - ogg_mux->active_pads--; - - /* Just gone to EOS. Flush existing page(s) */ - pad->eos = TRUE; - - while (ogg_stream_flush (&pad->stream, &page)) { - /* Place page into the per-pad queue */ - ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page, - pad->first_delta); - /* increment the page number counter */ - pad->pageno++; - /* mark other pages as delta */ - pad->first_delta = TRUE; - } - } - } - - pad->next_buffer = buf; - } - - /* we should have a buffer now, see if it is the best pad to - * pull on */ - if (pad->buffer || pad->next_buffer) { - if (gst_ogg_mux_compare_pads (ogg_mux, bestpad, pad) > 0) { - GST_LOG_OBJECT (data->pad, - "new best pad, with buffers %" GST_PTR_FORMAT - " and %" GST_PTR_FORMAT, pad->buffer, pad->next_buffer); - - bestpad = pad; - } - } else if (!pad->eos) { - GST_LOG_OBJECT (data->pad, "hungry pad"); - still_hungry = pad; - } - } - - if (still_hungry) - /* drop back into collectpads... */ - return still_hungry; - else - return bestpad; -} - -static GList * -gst_ogg_mux_get_headers (GstOggPad * pad) -{ - GList *res = NULL; - GstOggMux *ogg_mux; - GstStructure *structure; - GstCaps *caps; - GstPad *thepad; - - thepad = pad->collect.pad; - - ogg_mux = GST_OGG_MUX (GST_PAD_PARENT (thepad)); - - GST_LOG_OBJECT (thepad, "getting headers"); - - caps = gst_pad_get_negotiated_caps (thepad); - if (caps != NULL) { - const GValue *streamheader; - - structure = gst_caps_get_structure (caps, 0); - if (strcmp (gst_structure_get_name (structure), "video/x-dirac") == 0) { - GstBuffer *buf = gst_buffer_new_and_alloc (16); - int fps_n = 12; - int fps_d = 1; - - gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d); - - memcpy (GST_BUFFER_DATA (buf), "KW-DIRAC", 8); - GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + 8, fps_n); - GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + 12, fps_d); - - res = g_list_append (res, buf); - - //res = g_list_append (res, gst_buffer_ref(pad->buffer)); - } else { - streamheader = gst_structure_get_value (structure, "streamheader"); - if (streamheader != NULL) { - GST_LOG_OBJECT (thepad, "got header"); - if (G_VALUE_TYPE (streamheader) == GST_TYPE_ARRAY) { - GArray *bufarr = g_value_peek_pointer (streamheader); - gint i; - - GST_LOG_OBJECT (thepad, "got fixed list"); - - for (i = 0; i < bufarr->len; i++) { - GValue *bufval = &g_array_index (bufarr, GValue, i); - - GST_LOG_OBJECT (thepad, "item %d", i); - if (G_VALUE_TYPE (bufval) == GST_TYPE_BUFFER) { - GstBuffer *buf = g_value_peek_pointer (bufval); - - GST_LOG_OBJECT (thepad, "adding item %d to header list", i); - - gst_buffer_ref (buf); - res = g_list_append (res, buf); - } - } - } else { - GST_LOG_OBJECT (thepad, "streamheader is not fixed list"); - } - } else { - GST_LOG_OBJECT (thepad, "caps don't have streamheader"); - } - } - gst_caps_unref (caps); - } else { - GST_LOG_OBJECT (thepad, "got empty caps as negotiated format"); - } - return res; -} - -static GstCaps * -gst_ogg_mux_set_header_on_caps (GstCaps * caps, GList * buffers) -{ - GstStructure *structure; - GValue array = { 0 }; - GList *walk = buffers; - - caps = gst_caps_make_writable (caps); - - structure = gst_caps_get_structure (caps, 0); - - /* put buffers in a fixed list */ - g_value_init (&array, GST_TYPE_ARRAY); - - while (walk) { - GstBuffer *buf = GST_BUFFER (walk->data); - GstBuffer *copy; - GValue value = { 0 }; - - walk = walk->next; - - /* mark buffer */ - GST_LOG ("Setting IN_CAPS on buffer of length %d", GST_BUFFER_SIZE (buf)); - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS); - - g_value_init (&value, GST_TYPE_BUFFER); - copy = gst_buffer_copy (buf); - gst_value_set_buffer (&value, copy); - gst_buffer_unref (copy); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - } - gst_structure_set_value (structure, "streamheader", &array); - g_value_unset (&array); - - return caps; -} - -/* - * For each pad we need to write out one (small) header in one - * page that allows decoders to identify the type of the stream. - * After that we need to write out all extra info for the decoders. - * In the case of a codec that also needs data as configuration, we can - * find that info in the streamcaps. - * After writing the headers we must start a new page for the data. - */ -static GstFlowReturn -gst_ogg_mux_send_headers (GstOggMux * mux) -{ - GSList *walk; - GList *hbufs, *hwalk; - GstCaps *caps; - GstFlowReturn ret; - - hbufs = NULL; - ret = GST_FLOW_OK; - - GST_LOG_OBJECT (mux, "collecting headers"); - - walk = mux->collect->data; - while (walk) { - GstOggPad *pad; - GstPad *thepad; - - pad = (GstOggPad *) walk->data; - thepad = pad->collect.pad; - - walk = g_slist_next (walk); - - GST_LOG_OBJECT (mux, "looking at pad %s:%s", GST_DEBUG_PAD_NAME (thepad)); - - /* if the pad has no buffer, we don't care */ - if (pad->buffer == NULL && pad->next_buffer == NULL) - continue; - - /* now figure out the headers */ - pad->headers = gst_ogg_mux_get_headers (pad); - } - - GST_LOG_OBJECT (mux, "creating BOS pages"); - walk = mux->collect->data; - while (walk) { - GstOggPad *pad; - GstBuffer *buf; - ogg_packet packet; - ogg_page page; - GstPad *thepad; - GstCaps *caps; - GstStructure *structure; - GstBuffer *hbuf; - - pad = (GstOggPad *) walk->data; - thepad = pad->collect.pad; - caps = gst_pad_get_negotiated_caps (thepad); - structure = gst_caps_get_structure (caps, 0); - - walk = walk->next; - - pad->packetno = 0; - - GST_LOG_OBJECT (thepad, "looping over headers"); - - if (pad->headers) { - buf = GST_BUFFER (pad->headers->data); - pad->headers = g_list_remove (pad->headers, buf); - } else if (pad->buffer) { - buf = pad->buffer; - gst_buffer_ref (buf); - } else if (pad->next_buffer) { - buf = pad->next_buffer; - gst_buffer_ref (buf); - } else { - /* fixme -- should be caught in the previous list traversal. */ - GST_OBJECT_LOCK (pad); - g_critical ("No headers or buffers on pad %s:%s", - GST_DEBUG_PAD_NAME (pad)); - GST_OBJECT_UNLOCK (pad); - continue; - } - - /* create a packet from the buffer */ - packet.packet = GST_BUFFER_DATA (buf); - packet.bytes = GST_BUFFER_SIZE (buf); - packet.granulepos = GST_BUFFER_OFFSET_END (buf); - if (packet.granulepos == -1) - packet.granulepos = 0; - /* mark BOS and packet number */ - packet.b_o_s = (pad->packetno == 0); - packet.packetno = pad->packetno++; - /* mark EOS */ - packet.e_o_s = 0; - - /* swap the packet in */ - ogg_stream_packetin (&pad->stream, &packet); - gst_buffer_unref (buf); - - GST_LOG_OBJECT (thepad, "flushing out BOS page"); - if (!ogg_stream_flush (&pad->stream, &page)) - g_critical ("Could not flush BOS page"); - - hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE); - - GST_LOG_OBJECT (mux, "swapped out page with mime type %s", - gst_structure_get_name (structure)); - - /* quick hack: put Theora and Dirac video pages at the front. - * Ideally, we would have a settable enum for which Ogg - * profile we work with, and order based on that. - * (FIXME: if there is more than one video stream, shouldn't we only put - * one's BOS into the first page, followed by an audio stream's BOS, and - * only then followed by the remaining video and audio streams?) */ - if (gst_structure_has_name (structure, "video/x-theora")) { - GST_DEBUG_OBJECT (thepad, "putting %s page at the front", "Theora"); - hbufs = g_list_prepend (hbufs, hbuf); - } else if (gst_structure_has_name (structure, "video/x-dirac")) { - GST_DEBUG_OBJECT (thepad, "putting %s page at the front", "Dirac"); - hbufs = g_list_prepend (hbufs, hbuf); - } else { - hbufs = g_list_append (hbufs, hbuf); - } - gst_caps_unref (caps); - } - - GST_LOG_OBJECT (mux, "creating next headers"); - walk = mux->collect->data; - while (walk) { - GstOggPad *pad; - GstPad *thepad; - - pad = (GstOggPad *) walk->data; - thepad = pad->collect.pad; - - walk = walk->next; - - GST_LOG_OBJECT (mux, "looping over headers for pad %s:%s", - GST_DEBUG_PAD_NAME (thepad)); - - hwalk = pad->headers; - while (hwalk) { - GstBuffer *buf = GST_BUFFER (hwalk->data); - ogg_packet packet; - ogg_page page; - - hwalk = hwalk->next; - - /* create a packet from the buffer */ - packet.packet = GST_BUFFER_DATA (buf); - packet.bytes = GST_BUFFER_SIZE (buf); - packet.granulepos = GST_BUFFER_OFFSET_END (buf); - if (packet.granulepos == -1) - packet.granulepos = 0; - /* mark BOS and packet number */ - packet.b_o_s = (pad->packetno == 0); - packet.packetno = pad->packetno++; - /* mark EOS */ - packet.e_o_s = 0; - - /* swap the packet in */ - ogg_stream_packetin (&pad->stream, &packet); - gst_buffer_unref (buf); - - /* if last header, flush page */ - if (hwalk == NULL) { - GST_LOG_OBJECT (mux, - "flushing page as packet %" G_GUINT64_FORMAT " is first or " - "last packet", pad->packetno); - while (ogg_stream_flush (&pad->stream, &page)) { - GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE); - - GST_LOG_OBJECT (mux, "swapped out page"); - hbufs = g_list_append (hbufs, hbuf); - } - } else { - GST_LOG_OBJECT (mux, "try to swap out page"); - /* just try to swap out a page then */ - while (ogg_stream_pageout (&pad->stream, &page) > 0) { - GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE); - - GST_LOG_OBJECT (mux, "swapped out page"); - hbufs = g_list_append (hbufs, hbuf); - } - } - } - g_list_free (pad->headers); - pad->headers = NULL; - } - /* hbufs holds all buffers for the headers now */ - - /* create caps with the buffers */ - caps = gst_pad_get_caps (mux->srcpad); - if (caps) { - caps = gst_ogg_mux_set_header_on_caps (caps, hbufs); - gst_pad_set_caps (mux->srcpad, caps); - gst_caps_unref (caps); - } - /* and send the buffers */ - hwalk = hbufs; - while (hwalk) { - GstBuffer *buf = GST_BUFFER (hwalk->data); - - hwalk = hwalk->next; - - if ((ret = gst_ogg_mux_push_buffer (mux, buf)) != GST_FLOW_OK) - break; - } - g_list_free (hbufs); - - return ret; -} - -/* this function is called to process data on the best pending pad. - * - * basic idea: - * - * 1) store the selected pad and keep on pulling until we fill a - * complete ogg page or the ogg page is filled above the max-delay - * threshold. This is needed because the ogg spec says that - * you should fill a complete page with data from the same logical - * stream. When the page is filled, go back to 1). - * 2) before filling a page, read ahead one more buffer to see if this - * packet is the last of the stream. We need to do this because the ogg - * spec mandates that the last packet should have the EOS flag set before - * sending it to ogg. if pad->buffer is NULL we need to wait to find out - * whether there are any more buffers. - * 3) pages get queued on a per-pad queue. Every time a page is queued, a - * dequeue is called, which will dequeue the oldest page on any pad, provided - * that ALL pads have at least one marked page in the queue (or remaining - * pads are at EOS) - */ -static GstFlowReturn -gst_ogg_mux_process_best_pad (GstOggMux * ogg_mux, GstOggPad * best) -{ - gboolean delta_unit; - GstFlowReturn ret; - gint64 granulepos = 0; - GstClockTime timestamp, gp_time; - - GST_LOG_OBJECT (ogg_mux, "best pad %" GST_PTR_FORMAT - ", currently pulling from %" GST_PTR_FORMAT, best->collect.pad, - ogg_mux->pulling); - - /* best->buffer is non-NULL, either the pad is EOS's or there is a next - * buffer */ - if (best->next_buffer == NULL && !best->eos) { - GST_WARNING_OBJECT (ogg_mux, "no subsequent buffer and EOS not reached"); - return GST_FLOW_WRONG_STATE; - } - - /* if we were already pulling from one pad, but the new "best" buffer is - * from another pad, we need to check if we have reason to flush a page - * for the pad we were pulling from before */ - if (ogg_mux->pulling && best && - ogg_mux->pulling != best && ogg_mux->pulling->buffer) { - GstOggPad *pad = ogg_mux->pulling; - - GstClockTime last_ts = GST_BUFFER_END_TIME (pad->buffer); - - /* if the next packet in the current page is going to make the page - * too long, we need to flush */ - if (last_ts > ogg_mux->next_ts + ogg_mux->max_delay) { - ogg_page page; - - GST_LOG_OBJECT (pad->collect.pad, - GST_GP_FORMAT " stored packet %" G_GINT64_FORMAT - " will make page too long, flushing", - GST_BUFFER_OFFSET_END (pad->buffer), pad->stream.packetno); - - while (ogg_stream_flush (&pad->stream, &page)) { - /* end time of this page is the timestamp of the next buffer */ - ogg_mux->pulling->timestamp_end = GST_BUFFER_TIMESTAMP (pad->buffer); - /* Place page into the per-pad queue */ - ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page, - pad->first_delta); - /* increment the page number counter */ - pad->pageno++; - /* mark other pages as delta */ - pad->first_delta = TRUE; - } - pad->new_page = TRUE; - ogg_mux->pulling = NULL; - } - } - - /* if we don't know which pad to pull on, use the best one */ - if (ogg_mux->pulling == NULL) { - ogg_mux->pulling = best; - GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, "pulling from best pad"); - - /* remember timestamp and gp time of first buffer for this new pad */ - if (ogg_mux->pulling != NULL) { - ogg_mux->next_ts = GST_BUFFER_TIMESTAMP (ogg_mux->pulling->buffer); - GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, "updated times, next ts %" - GST_TIME_FORMAT, GST_TIME_ARGS (ogg_mux->next_ts)); - } else { - /* no pad to pull on, send EOS */ - gst_pad_push_event (ogg_mux->srcpad, gst_event_new_eos ()); - return GST_FLOW_WRONG_STATE; - } - } - - if (ogg_mux->need_headers) { - ret = gst_ogg_mux_send_headers (ogg_mux); - ogg_mux->need_headers = FALSE; - } - - /* we are pulling from a pad, continue to do so until a page - * has been filled and queued */ - if (ogg_mux->pulling != NULL) { - ogg_packet packet; - ogg_page page; - GstBuffer *buf, *tmpbuf; - GstOggPad *pad = ogg_mux->pulling; - gint64 duration; - gboolean force_flush; - - GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, "pulling from pad"); - - /* now see if we have a buffer */ - buf = pad->buffer; - if (buf == NULL) { - GST_DEBUG_OBJECT (ogg_mux, "pad was EOS"); - ogg_mux->pulling = NULL; - return GST_FLOW_OK; - } - - delta_unit = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); - duration = GST_BUFFER_DURATION (buf); - - /* if the current "next timestamp" on the pad is unset, then this is the - * first packet on the new page. Update our pad's page timestamp */ - if (ogg_mux->pulling->timestamp == GST_CLOCK_TIME_NONE) { - ogg_mux->pulling->timestamp = GST_BUFFER_TIMESTAMP (buf); - GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, - "updated pad timestamp to %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); - } - /* create a packet from the buffer */ - packet.packet = GST_BUFFER_DATA (buf); - packet.bytes = GST_BUFFER_SIZE (buf); - packet.granulepos = GST_BUFFER_OFFSET_END (buf); - if (packet.granulepos == -1) - packet.granulepos = 0; - /* mark BOS and packet number */ - packet.b_o_s = (pad->packetno == 0); - packet.packetno = pad->packetno++; - GST_LOG_OBJECT (pad->collect.pad, GST_GP_FORMAT - " packet %" G_GINT64_FORMAT " (%ld bytes) created from buffer", - packet.granulepos, packet.packetno, packet.bytes); - - packet.e_o_s = (pad->eos ? 1 : 0); - tmpbuf = NULL; - - /* we flush when we see a new keyframe */ - force_flush = (pad->prev_delta && !delta_unit); - if (duration != -1) { - pad->duration += duration; - /* if page duration exceeds max, flush page */ - if (pad->duration > ogg_mux->max_page_delay) { - force_flush = TRUE; - pad->duration = 0; - } - } - - if (GST_BUFFER_IS_DISCONT (buf)) { - packet.packetno++; - /* No public API for this; hack things in */ - pad->stream.pageno++; - force_flush = TRUE; - } - - /* flush the currently built page if necessary */ - if (force_flush) { - GST_LOG_OBJECT (pad->collect.pad, - GST_GP_FORMAT " forced flush of page before this packet", - GST_BUFFER_OFFSET_END (pad->buffer)); - while (ogg_stream_flush (&pad->stream, &page)) { - /* end time of this page is the timestamp of the next buffer */ - ogg_mux->pulling->timestamp_end = GST_BUFFER_TIMESTAMP (pad->buffer); - ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page, - pad->first_delta); - - /* increment the page number counter */ - pad->pageno++; - /* mark other pages as delta */ - pad->first_delta = TRUE; - } - pad->new_page = TRUE; - } - - /* if this is the first packet of a new page figure out the delta flag */ - if (pad->new_page) { - if (delta_unit) { - /* mark the page as delta */ - pad->first_delta = TRUE; - } else { - /* got a keyframe */ - if (ogg_mux->delta_pad == pad) { - /* if we get it on the pad with deltaunits, - * we mark the page as non delta */ - pad->first_delta = FALSE; - } else if (ogg_mux->delta_pad != NULL) { - /* if there are pads with delta frames, we - * must mark this one as delta */ - pad->first_delta = TRUE; - } else { - pad->first_delta = FALSE; - } - } - pad->new_page = FALSE; - } - - /* save key unit to track delta->key unit transitions */ - pad->prev_delta = delta_unit; - - /* swap the packet in */ - if (packet.e_o_s == 1) - GST_DEBUG_OBJECT (pad->collect.pad, "swapping in EOS packet"); - if (packet.b_o_s == 1) - GST_DEBUG_OBJECT (pad->collect.pad, "swapping in BOS packet"); - - ogg_stream_packetin (&pad->stream, &packet); - - gp_time = GST_BUFFER_OFFSET (pad->buffer); - granulepos = GST_BUFFER_OFFSET_END (pad->buffer); - timestamp = GST_BUFFER_TIMESTAMP (pad->buffer); - - GST_LOG_OBJECT (pad->collect.pad, - GST_GP_FORMAT " packet %" G_GINT64_FORMAT ", gp time %" - GST_TIME_FORMAT ", timestamp %" GST_TIME_FORMAT " packetin'd", - granulepos, packet.packetno, GST_TIME_ARGS (gp_time), - GST_TIME_ARGS (timestamp)); - /* don't need the old buffer anymore */ - gst_buffer_unref (pad->buffer); - /* store new readahead buffer */ - pad->buffer = tmpbuf; - - /* let ogg write out the pages now. The packet we got could end - * up in more than one page so we need to write them all */ - if (ogg_stream_pageout (&pad->stream, &page) > 0) { - /* we have a new page, so we need to timestamp it correctly. - * if this fresh packet ends on this page, then the page's granulepos - * comes from that packet, and we should set this buffer's timestamp */ - - GST_LOG_OBJECT (pad->collect.pad, - GST_GP_FORMAT " packet %" G_GINT64_FORMAT ", time %" - GST_TIME_FORMAT ") caused new page", - granulepos, packet.packetno, GST_TIME_ARGS (timestamp)); - GST_LOG_OBJECT (pad->collect.pad, - GST_GP_FORMAT " new page %ld", ogg_page_granulepos (&page), - pad->stream.pageno); - - if (ogg_page_granulepos (&page) == granulepos) { - /* the packet we streamed in finishes on the current page, - * because the page's granulepos is the granulepos of the last - * packet completed on that page, - * so update the timestamp that we will give to the page */ - GST_LOG_OBJECT (pad->collect.pad, - GST_GP_FORMAT - " packet finishes on current page, updating gp time to %" - GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (gp_time)); - pad->gp_time = gp_time; - } else { - GST_LOG_OBJECT (pad->collect.pad, - GST_GP_FORMAT - " packet spans beyond current page, keeping old gp time %" - GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (pad->gp_time)); - } - - /* push the page */ - /* end time of this page is the timestamp of the next buffer */ - pad->timestamp_end = timestamp; - ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page, pad->first_delta); - pad->pageno++; - /* mark next pages as delta */ - pad->first_delta = TRUE; - - /* use an inner loop here to flush the remaining pages and - * mark them as delta frames as well */ - while (ogg_stream_pageout (&pad->stream, &page) > 0) { - if (ogg_page_granulepos (&page) == granulepos) { - /* the page has taken up the new packet completely, which means - * the packet ends the page and we can update the gp time - * before pushing out */ - pad->gp_time = gp_time; - } - - /* we have a complete page now, we can push the page - * and make sure to pull on a new pad the next time around */ - ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page, - pad->first_delta); - /* increment the page number counter */ - pad->pageno++; - } - /* need a new page as well */ - pad->new_page = TRUE; - pad->duration = 0; - /* we're done pulling on this pad, make sure to choose a new - * pad for pulling in the next iteration */ - ogg_mux->pulling = NULL; - } - - /* Update the gp time, if necessary, since any future page will have at - * least this gp time. - */ - if (pad->gp_time < gp_time) { - pad->gp_time = gp_time; - GST_LOG_OBJECT (pad->collect.pad, - "Updated running gp time of pad %" GST_PTR_FORMAT - " to %" GST_TIME_FORMAT, pad->collect.pad, GST_TIME_ARGS (gp_time)); - } - } - - return GST_FLOW_OK; -} - -/** all_pads_eos: - * - * Checks if all pads are EOS'd by peeking. - * - * Returns TRUE if all pads are EOS. - */ -static gboolean -all_pads_eos (GstCollectPads * pads) -{ - GSList *walk; - gboolean alleos = TRUE; - - walk = pads->data; - while (walk) { - GstBuffer *buf; - GstCollectData *data = (GstCollectData *) walk->data; - - buf = gst_collect_pads_peek (pads, data); - if (buf) { - alleos = FALSE; - gst_buffer_unref (buf); - goto beach; - } - walk = walk->next; - } -beach: - return alleos; -} - -/* This function is called when there is data on all pads. - * - * It finds a pad to pull on, this is done by looking at the buffers - * to decide which one to use, and using the 'oldest' one first. It then calls - * gst_ogg_mux_process_best_pad() to process as much data as possible. - * - * If all the pads have received EOS, it flushes out all data by continually - * getting the best pad and calling gst_ogg_mux_process_best_pad() until they - * are all empty, and then sends EOS. - */ -static GstFlowReturn -gst_ogg_mux_collected (GstCollectPads * pads, GstOggMux * ogg_mux) -{ - GstOggPad *best; - GstFlowReturn ret; - gint activebefore; - - GST_LOG_OBJECT (ogg_mux, "collected"); - - activebefore = ogg_mux->active_pads; - - /* queue buffers on all pads; find a buffer with the lowest timestamp */ - best = gst_ogg_mux_queue_pads (ogg_mux); - if (best && !best->buffer) { - GST_DEBUG_OBJECT (ogg_mux, "No buffer available on best pad"); - return GST_FLOW_OK; - } - - if (!best) { - return GST_FLOW_WRONG_STATE; - } - - ret = gst_ogg_mux_process_best_pad (ogg_mux, best); - - if (ogg_mux->active_pads < activebefore) { - /* If the active pad count went down, this mean at least one pad has gone - * EOS. Since CollectPads only calls _collected() once when all pads are - * EOS, and our code doesn't _pop() from all pads we need to check that by - * peeking on all pads, else we won't be called again and the muxing will - * not terminate (push out EOS). */ - - /* if all the pads have been removed, flush all pending data */ - if ((ret == GST_FLOW_OK) && all_pads_eos (pads)) { - GST_LOG_OBJECT (ogg_mux, "no pads remaining, flushing data"); - - do { - best = gst_ogg_mux_queue_pads (ogg_mux); - if (best) - ret = gst_ogg_mux_process_best_pad (ogg_mux, best); - } while ((ret == GST_FLOW_OK) && (best != NULL)); - - GST_DEBUG_OBJECT (ogg_mux, "Pushing EOS"); - gst_pad_push_event (ogg_mux->srcpad, gst_event_new_eos ()); - } - } - - return ret; -} - -static void -gst_ogg_mux_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstOggMux *ogg_mux; - - ogg_mux = GST_OGG_MUX (object); - - switch (prop_id) { - case ARG_MAX_DELAY: - g_value_set_uint64 (value, ogg_mux->max_delay); - break; - case ARG_MAX_PAGE_DELAY: - g_value_set_uint64 (value, ogg_mux->max_page_delay); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_ogg_mux_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstOggMux *ogg_mux; - - ogg_mux = GST_OGG_MUX (object); - - switch (prop_id) { - case ARG_MAX_DELAY: - ogg_mux->max_delay = g_value_get_uint64 (value); - break; - case ARG_MAX_PAGE_DELAY: - ogg_mux->max_page_delay = g_value_get_uint64 (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* reset all variables in the ogg pads. */ -static void -gst_ogg_mux_init_collectpads (GstCollectPads * collect) -{ - GSList *walk; - - walk = collect->data; - while (walk) { - GstOggPad *oggpad = (GstOggPad *) walk->data; - - ogg_stream_init (&oggpad->stream, oggpad->serial); - oggpad->packetno = 0; - oggpad->pageno = 0; - oggpad->eos = FALSE; - /* we assume there will be some control data first for this pad */ - oggpad->state = GST_OGG_PAD_STATE_CONTROL; - oggpad->new_page = TRUE; - oggpad->first_delta = FALSE; - oggpad->prev_delta = FALSE; - oggpad->pagebuffers = g_queue_new (); - - walk = g_slist_next (walk); - } -} - -/* Clear all buffers from the collectpads object */ -static void -gst_ogg_mux_clear_collectpads (GstCollectPads * collect) -{ - GSList *walk; - - for (walk = collect->data; walk; walk = g_slist_next (walk)) { - GstOggPad *oggpad = (GstOggPad *) walk->data; - GstBuffer *buf; - - ogg_stream_clear (&oggpad->stream); - - while ((buf = g_queue_pop_head (oggpad->pagebuffers)) != NULL) { - gst_buffer_unref (buf); - } - g_queue_free (oggpad->pagebuffers); - oggpad->pagebuffers = NULL; - } -} - -static GstStateChangeReturn -gst_ogg_mux_change_state (GstElement * element, GstStateChange transition) -{ - GstOggMux *ogg_mux; - GstStateChangeReturn ret; - - ogg_mux = GST_OGG_MUX (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_ogg_mux_clear (ogg_mux); - gst_ogg_mux_init_collectpads (ogg_mux->collect); - gst_collect_pads_start (ogg_mux->collect); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_collect_pads_stop (ogg_mux->collect); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_ogg_mux_clear_collectpads (ogg_mux->collect); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - -gboolean -gst_ogg_mux_plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (gst_ogg_mux_debug, "oggmux", 0, "ogg muxer"); - - return gst_element_register (plugin, "oggmux", GST_RANK_NONE, - GST_TYPE_OGG_MUX); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/ogg/gstoggmux.h --- a/gst_plugins_base/ext/ogg/gstoggmux.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* OGG muxer plugin for GStreamer - * Copyright (C) 2004 Wim Taymans - * Copyright (C) 2006 Thomas Vander Stichele - * - * 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. - */ - -#ifndef __GST_OGG_MUX_H__ -#define __GST_OGGEMUX_H__ - -#include - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_OGG_MUX (gst_ogg_mux_get_type()) -#define GST_OGG_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_MUX, GstOggMux)) -#define GST_OGG_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_MUX, GstOggMux)) -#define GST_IS_OGG_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_MUX)) -#define GST_IS_OGG_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_MUX)) - -typedef struct _GstOggMux GstOggMux; -typedef struct _GstOggMuxClass GstOggMuxClass; - -typedef enum -{ - GST_OGG_PAD_STATE_CONTROL = 0, - GST_OGG_PAD_STATE_DATA = 1 -} -GstOggPadState; - -/* all information needed for one ogg stream */ -typedef struct -{ - GstCollectData collect; /* we extend the CollectData */ - - /* These two buffers make a very simple queue - they enter as 'next_buffer' - * and (usually) leave as 'buffer', except at EOS, when buffer will be NULL */ - GstBuffer *buffer; /* the first waiting buffer for the pad */ - GstBuffer *next_buffer; /* the second waiting buffer for the pad */ - - gint serial; - ogg_stream_state stream; - gint64 packetno; /* number of next packet */ - gint64 pageno; /* number of next page */ - guint64 duration; /* duration of current page */ - gboolean eos; - gint64 offset; - GstClockTime timestamp; /* timestamp of the first packet on the next - * page to be dequeued */ - GstClockTime timestamp_end; /* end timestamp of last complete packet on - the next page to be dequeued */ - GstClockTime gp_time; /* time corresponding to the gp value of the - last complete packet on the next page to be - dequeued */ - - GstOggPadState state; /* state of the pad */ - - GList *headers; - - GQueue *pagebuffers; /* List of pages in buffers ready for pushing */ - - gboolean new_page; /* starting a new page */ - gboolean first_delta; /* was the first packet in the page a delta */ - gboolean prev_delta; /* was the previous buffer a delta frame */ -} -GstOggPad; - -struct _GstOggMux -{ - GstElement element; - - /* source pad */ - GstPad *srcpad; - - /* sinkpads */ - GstCollectPads *collect; - - /* number of pads which have not received EOS */ - gint active_pads; - - /* the pad we are currently using to fill a page */ - GstOggPad *pulling; - - /* next timestamp for the page */ - GstClockTime next_ts; - - /* Last timestamp actually output on src pad */ - GstClockTime last_ts; - - /* offset in stream */ - guint64 offset; - - /* need_headers */ - gboolean need_headers; - - guint64 max_delay; - guint64 max_page_delay; - - GstOggPad *delta_pad; /* when a delta frame is detected on a stream, we mark - pages as delta frames up to the page that has the - keyframe */ - -}; - -struct _GstOggMuxClass -{ - GstElementClass parent_class; -}; - -GType gst_ogg_mux_get_type (void); - -G_END_DECLS - -#endif /* __GST_OGG_MUX_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/ogg/gstoggparse.c --- a/gst_plugins_base/ext/ogg/gstoggparse.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,695 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Michael Smith - * - * gstoggparse.c: ogg stream parser - * - * 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. - */ - -/* This ogg parser is essentially a subset of the ogg demuxer - rather than - * fully demuxing into packets, we only parse out the pages, create one - * GstBuffer per page, set all the appropriate flags on those pages, set caps - * appropriately (particularly the 'streamheader' which gives all the header - * pages required for initialing decode). - * - * It's dramatically simpler than the full demuxer as it does not support - * seeking. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include - -static const GstElementDetails gst_ogg_parse_details = -GST_ELEMENT_DETAILS ("Ogg parser", - "Codec/Parser", - "parse ogg streams into pages (info about ogg: http://xiph.org)", - "Michael Smith "); - -GST_DEBUG_CATEGORY_STATIC (gst_ogg_parse_debug); -#define GST_CAT_DEFAULT gst_ogg_parse_debug - -#define GST_TYPE_OGG_PARSE (gst_ogg_parse_get_type()) -#define GST_OGG_PARSE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_PARSE, GstOggParse)) -#define GST_OGG_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_PARSE, GstOggParse)) -#define GST_IS_OGG_PARSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_PARSE)) -#define GST_IS_OGG_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_PARSE)) - -static GType gst_ogg_parse_get_type (void); - -typedef struct _GstOggParse GstOggParse; -typedef struct _GstOggParseClass GstOggParseClass; - -/* Each ogg logical stream has a GstOggStream associated with it */ -typedef struct -{ - /*ogg_stream_state stream; *//* We need this to get the packets out in order - to do codec identification, for various - codec-specific tasks */ - - gboolean in_headers; /* Initially true, false once we've read all the - headers for this logical stream */ - - guint32 serialno; /* Unique serial number of this stream */ - - GSList *headers; /* List of ogg pages that we'll set on caps */ - GSList *unknown_pages; /* List of pages we haven't yet classified */ -} GstOggStream; - -struct _GstOggParse -{ - GstElement element; - - GstPad *sinkpad; /* Sink pad we're reading data from */ - - GstPad *srcpad; /* Source pad we're writing to */ - - GSList *oggstreams; /* list of GstOggStreams for known streams */ - - gint64 offset; /* Current stream offset */ - - gboolean in_headers; /* Set if we're reading headers for streams */ - - gboolean last_page_not_bos; /* Set if we've seen a non-BOS page */ - - ogg_sync_state sync; /* Ogg page synchronisation */ - - GstCaps *caps; /* Our src caps */ -}; - -struct _GstOggParseClass -{ - GstElementClass parent_class; -}; - -static void gst_ogg_parse_base_init (gpointer g_class); -static void gst_ogg_parse_class_init (GstOggParseClass * klass); -static void gst_ogg_parse_init (GstOggParse * ogg); -static GstElementClass *parent_class = NULL; - -static GType -gst_ogg_parse_get_type (void) -{ - static GType ogg_parse_type = 0; - - if (!ogg_parse_type) { - static const GTypeInfo ogg_parse_info = { - sizeof (GstOggParseClass), - gst_ogg_parse_base_init, - NULL, - (GClassInitFunc) gst_ogg_parse_class_init, - NULL, - NULL, - sizeof (GstOggParse), - 0, - (GInstanceInitFunc) gst_ogg_parse_init, - }; - - ogg_parse_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOggParse", - &ogg_parse_info, 0); - } - return ogg_parse_type; -} - -static void -free_stream (GstOggStream * stream) -{ - g_slist_foreach (stream->headers, (GFunc) gst_mini_object_unref, NULL); - g_slist_foreach (stream->unknown_pages, (GFunc) gst_mini_object_unref, NULL); - - g_free (stream); -} - -static void -gst_ogg_parse_delete_all_streams (GstOggParse * ogg) -{ - g_slist_foreach (ogg->oggstreams, (GFunc) free_stream, NULL); - g_slist_free (ogg->oggstreams); - ogg->oggstreams = NULL; -} - -static GstOggStream * -gst_ogg_parse_new_stream (GstOggParse * parser, guint32 serialno) -{ - GstOggStream *ret; - - GST_DEBUG_OBJECT (parser, "creating new stream %08x", serialno); - - ret = g_new0 (GstOggStream, 1); - - ret->serialno = serialno; - ret->in_headers = 1; - - /* - if (ogg_stream_init (&ret->stream, serialno) != 0) { - GST_ERROR ("Could not initialize ogg_stream struct for serial %08lx.", - serialno); - return NULL; - } - */ - - parser->oggstreams = g_slist_append (parser->oggstreams, ret); - - return ret; -} - -static GstOggStream * -gst_ogg_parse_find_stream (GstOggParse * parser, guint32 serialno) -{ - GSList *l; - - for (l = parser->oggstreams; l != NULL; l = l->next) { - GstOggStream *stream = (GstOggStream *) l->data; - - if (stream->serialno == serialno) - return stream; - } - return NULL; -} - -/* signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0 - /* FILL ME */ -}; - -static GstStaticPadTemplate ogg_parse_src_template_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/ogg") - ); - -static GstStaticPadTemplate ogg_parse_sink_template_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/ogg") - ); - -static void gst_ogg_parse_dispose (GObject * object); -static GstStateChangeReturn gst_ogg_parse_change_state (GstElement * element, - GstStateChange transition); -static GstFlowReturn gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer); - -static void -gst_ogg_parse_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_ogg_parse_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&ogg_parse_sink_template_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&ogg_parse_src_template_factory)); -} - -static void -gst_ogg_parse_class_init (GstOggParseClass * klass) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gstelement_class->change_state = gst_ogg_parse_change_state; - - gobject_class->dispose = gst_ogg_parse_dispose; -} - -static void -gst_ogg_parse_init (GstOggParse * ogg) -{ - /* create the sink and source pads */ - ogg->sinkpad = - gst_pad_new_from_static_template (&ogg_parse_sink_template_factory, - "sink"); - ogg->srcpad = - gst_pad_new_from_static_template (&ogg_parse_src_template_factory, "src"); - - /* TODO: Are there any events we must handle? */ - /* gst_pad_set_event_function (ogg->sinkpad, gst_ogg_parse_handle_event); */ - gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_parse_chain); - - gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad); - gst_element_add_pad (GST_ELEMENT (ogg), ogg->srcpad); - - ogg->oggstreams = NULL; -} - -static void -gst_ogg_parse_dispose (GObject * object) -{ - GstOggParse *ogg = GST_OGG_PARSE (object); - - GST_LOG_OBJECT (ogg, "Disposing of object %p", ogg); - - ogg_sync_clear (&ogg->sync); - gst_ogg_parse_delete_all_streams (ogg); - - if (ogg->caps) { - gst_caps_unref (ogg->caps); - ogg->caps = NULL; - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -/* submit the given buffer to the ogg sync. - * - * Returns the number of bytes submited. - */ -static gint -gst_ogg_parse_submit_buffer (GstOggParse * ogg, GstBuffer * buffer) -{ - guint size; - guint8 *data; - gchar *oggbuffer; - - size = GST_BUFFER_SIZE (buffer); - data = GST_BUFFER_DATA (buffer); - - /* We now have a buffer, submit it to the ogg sync layer */ - oggbuffer = ogg_sync_buffer (&ogg->sync, size); - memcpy (oggbuffer, data, size); - ogg_sync_wrote (&ogg->sync, size); - - /* We've copied all the neccesary data, so we're done with the buffer */ - gst_buffer_unref (buffer); - - return size; -} - -static void -gst_ogg_parse_append_header (GValue * array, GstBuffer * buf) -{ - GValue value = { 0 }; - /* We require a copy to avoid circular refcounts */ - GstBuffer *buffer = gst_buffer_copy (buf); - - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS); - - g_value_init (&value, GST_TYPE_BUFFER); - gst_value_set_buffer (&value, buffer); - gst_value_array_append_value (array, &value); - g_value_unset (&value); - -} - -typedef enum -{ - PAGE_HEADER, /* Header page */ - PAGE_DATA, /* Data page */ - PAGE_PENDING, /* We don't know yet, we'll have to see some future pages */ -} page_type; - -static page_type -gst_ogg_parse_is_header (GstOggParse * ogg, GstOggStream * stream, - ogg_page * page) -{ - ogg_int64_t gpos = ogg_page_granulepos (page); - - if (gpos < 0) - return PAGE_PENDING; - - /* This is good enough for now, but technically requires codec-specific - * behaviour to be perfect. This is where we need the mooted library for - * this stuff, which nobody has written. - */ - if (gpos > 0) - return PAGE_DATA; - else - return PAGE_HEADER; -} - -static GstBuffer * -gst_ogg_parse_buffer_from_page (ogg_page * page, - guint64 offset, gboolean delta, GstClockTime timestamp) -{ - int size = page->header_len + page->body_len; - GstBuffer *buf = gst_buffer_new_and_alloc (size); - - memcpy (GST_BUFFER_DATA (buf), page->header, page->header_len); - memcpy (GST_BUFFER_DATA (buf) + page->header_len, page->body, page->body_len); - - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_OFFSET (buf) = offset; - GST_BUFFER_OFFSET_END (buf) = offset + size; - - return buf; -} - - -/* Reads in buffers, parses them, reframes into one-buffer-per-ogg-page, submits - * pages to output pad. - */ -static GstFlowReturn -gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer) -{ - GstOggParse *ogg; - GstFlowReturn result = GST_FLOW_OK; - gint ret = -1; - guint32 serialno; - GstBuffer *pagebuffer; - GstClockTime buffertimestamp = GST_BUFFER_TIMESTAMP (buffer); - - ogg = GST_OGG_PARSE (GST_OBJECT_PARENT (pad)); - - GST_LOG_OBJECT (ogg, "Chain function received buffer of size %d", - GST_BUFFER_SIZE (buffer)); - - gst_ogg_parse_submit_buffer (ogg, buffer); - - while (ret != 0 && result == GST_FLOW_OK) { - ogg_page page; - - /* We use ogg_sync_pageseek() rather than ogg_sync_pageout() so that we can - * track how many bytes the ogg layer discarded (in the case of sync errors, - * etc.); this allows us to accurately track the current stream offset - */ - ret = ogg_sync_pageseek (&ogg->sync, &page); - if (ret == 0) { - /* need more data, that's fine... */ - break; - } else if (ret < 0) { - /* discontinuity; track how many bytes we skipped (-ret) */ - ogg->offset -= ret; - } else { -#ifndef GST_DISABLE_GST_DEBUG - gint64 granule = ogg_page_granulepos (&page); - int bos = ogg_page_bos (&page); -#endif - guint64 startoffset = ogg->offset; - - GST_LOG_OBJECT (ogg, "Timestamping outgoing buffer as %" GST_TIME_FORMAT, - GST_TIME_ARGS (buffertimestamp)); - /* Turn our page into a GstBuffer TODO: better timestamps? Requires format - * parsing. */ - pagebuffer = gst_ogg_parse_buffer_from_page (&page, startoffset, FALSE, - buffertimestamp); - - /* We read out 'ret' bytes, so we set the next offset appropriately */ - ogg->offset += ret; - - serialno = ogg_page_serialno (&page); - - GST_LOG_OBJECT (ogg, - "processing ogg page (serial %08x, pageno %ld, " - "granule pos %" G_GUINT64_FORMAT ", bos %d, offset %" - G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT ")", - serialno, ogg_page_pageno (&page), - granule, bos, startoffset, ogg->offset); - - if (ogg_page_bos (&page)) { - /* If we've seen this serialno before, this is technically an error, - * we log this case but accept it - this one replaces the previous - * stream with this serialno. We can do this since we're streaming, and - * not supporting seeking... - */ - GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno); - - if (stream != NULL) { - GST_LOG_OBJECT (ogg, "Incorrect stream; repeats serial number %u " - "at offset %lld", serialno, ogg->offset); - } - - if (ogg->last_page_not_bos) { - GST_LOG_OBJECT (ogg, "Deleting all referenced streams, found a new " - "chain starting with serial %u", serialno); - gst_ogg_parse_delete_all_streams (ogg); - } - - stream = gst_ogg_parse_new_stream (ogg, serialno); - - ogg->last_page_not_bos = FALSE; - - gst_buffer_ref (pagebuffer); - stream->headers = g_slist_append (stream->headers, pagebuffer); - - if (!ogg->in_headers) { - GST_LOG_OBJECT (ogg, "Found start of new chain at offset %llu", - startoffset); - ogg->in_headers = 1; - } - - /* For now, we just keep the header buffer in the stream->headers list; - * it actually gets output once we've collected the entire set - */ - } else { - /* Non-BOS page. Either: we're outside headers, and this isn't a - * header (normal data), outside headers and this is (error!), inside - * headers, this is (append header), or inside headers and this isn't - * (we've found the end of headers; flush the lot!) - * - * Before that, we flag that the last page seen (this one) was not a - * BOS page; that way we know that when we next see a BOS page it's a - * new chain, and we can flush all existing streams. - */ - page_type type; - GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno); - - if (!stream) { - GST_LOG_OBJECT (ogg, "Non-BOS page unexpectedly found at %lld", - ogg->offset); - goto failure; - } - - ogg->last_page_not_bos = TRUE; - - type = gst_ogg_parse_is_header (ogg, stream, &page); - - if (type == PAGE_PENDING && ogg->in_headers) { - gst_buffer_ref (pagebuffer); - - stream->unknown_pages = g_slist_append (stream->unknown_pages, - pagebuffer); - } else if (type == PAGE_HEADER) { - if (!ogg->in_headers) { - GST_LOG_OBJECT (ogg, "Header page unexpectedly found outside " - "headers at offset %lld", ogg->offset); - goto failure; - } else { - /* Append the header to the buffer list, after any unknown previous - * pages - */ - stream->headers = g_slist_concat (stream->headers, - stream->unknown_pages); - g_slist_free (stream->unknown_pages); - gst_buffer_ref (pagebuffer); - stream->headers = g_slist_append (stream->headers, pagebuffer); - } - } else { /* PAGE_DATA, or PAGE_PENDING but outside headers */ - if (ogg->in_headers) { - /* First non-header page... set caps, flush headers. - * - * First up, we build a single GValue list of all the pagebuffers - * we're using for the headers, in order. - * Then we set this on the caps structure. Then we can start pushing - * buffers for the headers, and finally we send this non-header - * page. - */ - GstCaps *caps; - GstStructure *structure; - GValue array = { 0 }; - gint count = 0; - gboolean found_pending_headers = FALSE; - GSList *l; - - g_value_init (&array, GST_TYPE_ARRAY); - - for (l = ogg->oggstreams; l != NULL; l = l->next) { - GstOggStream *stream = (GstOggStream *) l->data; - - if (g_slist_length (stream->headers) == 0) { - GST_LOG_OBJECT (ogg, "No primary header found for stream %u", - stream->serialno); - goto failure; - } - - gst_ogg_parse_append_header (&array, - GST_BUFFER (stream->headers->data)); - count++; - } - - for (l = ogg->oggstreams; l != NULL; l = l->next) { - GstOggStream *stream = (GstOggStream *) l->data; - int j; - - for (j = 1; j < g_slist_length (stream->headers); j++) { - gst_ogg_parse_append_header (&array, - GST_BUFFER (g_slist_nth_data (stream->headers, j))); - count++; - } - } - - caps = gst_pad_get_caps (ogg->srcpad); - caps = gst_caps_make_writable (caps); - - structure = gst_caps_get_structure (caps, 0); - gst_structure_set_value (structure, "streamheader", &array); - - gst_pad_set_caps (ogg->srcpad, caps); - - g_value_unset (&array); - - if (ogg->caps) - gst_caps_unref (ogg->caps); - ogg->caps = caps; - - GST_LOG_OBJECT (ogg, "Set \"streamheader\" caps with %d buffers " - "(one per page)", count); - - /* Now, we do the same thing, but push buffers... */ - for (l = ogg->oggstreams; l != NULL; l = l->next) { - GstOggStream *stream = (GstOggStream *) l->data; - GstBuffer *buf = GST_BUFFER (stream->headers->data); - - gst_buffer_set_caps (buf, caps); - - result = gst_pad_push (ogg->srcpad, buf); - if (result != GST_FLOW_OK) - return result; - } - for (l = ogg->oggstreams; l != NULL; l = l->next) { - GstOggStream *stream = (GstOggStream *) l->data; - int j; - - for (j = 1; j < g_slist_length (stream->headers); j++) { - GstBuffer *buf = - GST_BUFFER (g_slist_nth_data (stream->headers, j)); - gst_buffer_set_caps (buf, caps); - - result = gst_pad_push (ogg->srcpad, buf); - if (result != GST_FLOW_OK) - return result; - } - } - - ogg->in_headers = 0; - - /* And finally the pending data pages */ - for (l = ogg->oggstreams; l != NULL; l = l->next) { - GstOggStream *stream = (GstOggStream *) l->data; - GSList *k; - - if (stream->unknown_pages == NULL) - continue; - - if (found_pending_headers) { - GST_WARNING_OBJECT (ogg, "Incorrectly muxed headers found at " - "approximate offset %lld", ogg->offset); - } - found_pending_headers = TRUE; - - GST_LOG_OBJECT (ogg, "Pushing %d pending pages after headers", - g_slist_length (stream->unknown_pages) + 1); - - for (k = stream->unknown_pages; k != NULL; k = k->next) { - GstBuffer *buf; - - buf = GST_BUFFER (k->data); - gst_buffer_set_caps (buf, caps); - result = gst_pad_push (ogg->srcpad, buf); - if (result != GST_FLOW_OK) - return result; - } - g_slist_foreach (stream->unknown_pages, - (GFunc) gst_mini_object_unref, NULL); - g_slist_free (stream->unknown_pages); - stream->unknown_pages = NULL; - } - - gst_buffer_set_caps (pagebuffer, caps); - - result = gst_pad_push (ogg->srcpad, GST_BUFFER (pagebuffer)); - if (result != GST_FLOW_OK) - return result; - } else { - /* Normal data page, submit buffer */ - gst_buffer_set_caps (pagebuffer, ogg->caps); - result = gst_pad_push (ogg->srcpad, GST_BUFFER (pagebuffer)); - if (result != GST_FLOW_OK) - return result; - } - } - } - } - } - - return result; - -failure: - gst_pad_push_event (GST_PAD (ogg->srcpad), gst_event_new_eos ()); - return GST_FLOW_ERROR; -} - -static GstStateChangeReturn -gst_ogg_parse_change_state (GstElement * element, GstStateChange transition) -{ - GstOggParse *ogg; - GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; - - ogg = GST_OGG_PARSE (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - ogg_sync_init (&ogg->sync); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - ogg_sync_reset (&ogg->sync); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - result = parent_class->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_NULL: - ogg_sync_clear (&ogg->sync); - break; - default: - break; - } - return result; -} - -gboolean -gst_ogg_parse_plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (gst_ogg_parse_debug, "oggparse", 0, "ogg parser"); - - return gst_element_register (plugin, "oggparse", GST_RANK_NONE, - GST_TYPE_OGG_PARSE); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/ogg/gstogmparse.c --- a/gst_plugins_base/ext/ogg/gstogmparse.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,956 +0,0 @@ -/* GStreamer OGM parsing - * Copyright (C) 2004 Ronald Bultje - * Copyright (C) 2006 Tim-Philipp Müller - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include -#include -#include -#include - -GST_DEBUG_CATEGORY_STATIC (gst_ogm_parse_debug); -#define GST_CAT_DEFAULT gst_ogm_parse_debug - -#define GST_TYPE_OGM_VIDEO_PARSE (gst_ogm_video_parse_get_type()) -#define GST_IS_OGM_VIDEO_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_VIDEO_PARSE)) - -#define GST_TYPE_OGM_AUDIO_PARSE (gst_ogm_audio_parse_get_type()) -#define GST_IS_OGM_AUDIO_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_AUDIO_PARSE)) - -#define GST_TYPE_OGM_TEXT_PARSE (gst_ogm_text_parse_get_type()) -#define GST_IS_OGM_TEXT_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_TEXT_PARSE)) - -#define GST_TYPE_OGM_PARSE (gst_ogm_parse_get_type()) -#define GST_OGM_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_OGM_PARSE, GstOgmParse)) -#define GST_OGM_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_OGM_PARSE, GstOgmParse)) -#define GST_IS_OGM_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_PARSE)) -#define GST_IS_OGM_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_OGM_PARSE)) -#define GST_OGM_PARSE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_OGM_PARSE, GstOgmParseClass)) - -static const GstElementDetails gst_ogm_audio_parse_details = -GST_ELEMENT_DETAILS ("OGM audio stream parser", - "Codec/Decoder/Audio", - "parse an OGM audio header and stream", - "Ronald Bultje "); - -static const GstElementDetails gst_ogm_video_parse_details = -GST_ELEMENT_DETAILS ("OGM video stream parser", - "Codec/Decoder/Video", - "parse an OGM video header and stream", - "Ronald Bultje "); - -static const GstElementDetails gst_ogm_text_parse_details = -GST_ELEMENT_DETAILS ("OGM text stream parser", - "Codec/Decoder/Subtitle", - "parse an OGM text header and stream", - "Ronald Bultje "); - -typedef struct _stream_header_video -{ - gint32 width; - gint32 height; -} stream_header_video; - -typedef struct _stream_header_audio -{ - gint16 channels; - gint16 blockalign; - gint32 avgbytespersec; -} stream_header_audio; - -/* sizeof(stream_header) might differ due to structure packing and - * alignment differences on some architectures, so not using that */ -#define OGM_STREAM_HEADER_SIZE (8+4+4+8+8+4+4+4+8) - -typedef struct _stream_header -{ - gchar streamtype[8]; - gchar subtype[4 + 1]; - - /* size of the structure */ - gint32 size; - - /* in reference time */ - gint64 time_unit; - - gint64 samples_per_unit; - - /* in media time */ - gint32 default_len; - - gint32 buffersize; - gint32 bits_per_sample; - - union - { - stream_header_video video; - stream_header_audio audio; - /* text has no additional data */ - } s; -} stream_header; - -typedef struct _GstOgmParse -{ - GstElement element; - - /* pads */ - GstPad *srcpad, *sinkpad; - GstPadTemplate *srcpadtempl; - - /* we need to cache events that we receive before creating the source pad */ - GList *cached_events; - - /* audio or video */ - stream_header hdr; - - /* expected next granulepos (used for timestamp guessing) */ - guint64 next_granulepos; -} GstOgmParse; - -typedef struct _GstOgmParseClass -{ - GstElementClass parent_class; -} GstOgmParseClass; - -static GstStaticPadTemplate sink_factory_video = -GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-ogm-video")); -static GstStaticPadTemplate sink_factory_audio = -GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-ogm-audio")); -static GstStaticPadTemplate sink_factory_text = -GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-ogm-text")); -static GstPadTemplate *video_src_templ, *audio_src_templ, *text_src_templ; - -static GType gst_ogm_audio_parse_get_type (void); -static GType gst_ogm_video_parse_get_type (void); -static GType gst_ogm_text_parse_get_type (void); -static GType gst_ogm_parse_get_type (void); - -static void gst_ogm_audio_parse_base_init (GstOgmParseClass * klass); -static void gst_ogm_video_parse_base_init (GstOgmParseClass * klass); -static void gst_ogm_text_parse_base_init (GstOgmParseClass * klass); -static void gst_ogm_parse_class_init (GstOgmParseClass * klass); -static void gst_ogm_parse_init (GstOgmParse * ogm); -static void gst_ogm_video_parse_init (GstOgmParse * ogm); -static void gst_ogm_audio_parse_init (GstOgmParse * ogm); -static void gst_ogm_text_parse_init (GstOgmParse * ogm); - -static const GstQueryType *gst_ogm_parse_get_sink_querytypes (GstPad * pad); -static gboolean gst_ogm_parse_sink_event (GstPad * pad, GstEvent * event); -static gboolean gst_ogm_parse_sink_query (GstPad * pad, GstQuery * query); -static gboolean gst_ogm_parse_sink_convert (GstPad * pad, GstFormat src_format, - gint64 src_value, GstFormat * dest_format, gint64 * dest_value); - -static GstFlowReturn gst_ogm_parse_chain (GstPad * pad, GstBuffer * buffer); - -static GstStateChangeReturn gst_ogm_parse_change_state (GstElement * element, - GstStateChange transition); - -static GstElementClass *parent_class = NULL; - -static GType -gst_ogm_parse_get_type (void) -{ - static GType ogm_parse_type = 0; - - if (!ogm_parse_type) { - static const GTypeInfo ogm_parse_info = { - sizeof (GstOgmParseClass), - NULL, - NULL, - (GClassInitFunc) gst_ogm_parse_class_init, - NULL, - NULL, - sizeof (GstOgmParse), - 0, - (GInstanceInitFunc) gst_ogm_parse_init, - }; - - ogm_parse_type = - g_type_register_static (GST_TYPE_ELEMENT, - "GstOgmParse", &ogm_parse_info, 0); - } - - return ogm_parse_type; -} - -static GType -gst_ogm_audio_parse_get_type (void) -{ - static GType ogm_audio_parse_type = 0; - - if (!ogm_audio_parse_type) { - static const GTypeInfo ogm_audio_parse_info = { - sizeof (GstOgmParseClass), - (GBaseInitFunc) gst_ogm_audio_parse_base_init, - NULL, - NULL, - NULL, - NULL, - sizeof (GstOgmParse), - 0, - (GInstanceInitFunc) gst_ogm_audio_parse_init, - }; - - ogm_audio_parse_type = - g_type_register_static (GST_TYPE_OGM_PARSE, - "GstOgmAudioParse", &ogm_audio_parse_info, 0); - } - - return ogm_audio_parse_type; -} - -static GType -gst_ogm_video_parse_get_type (void) -{ - static GType ogm_video_parse_type = 0; - - if (!ogm_video_parse_type) { - static const GTypeInfo ogm_video_parse_info = { - sizeof (GstOgmParseClass), - (GBaseInitFunc) gst_ogm_video_parse_base_init, - NULL, - NULL, - NULL, - NULL, - sizeof (GstOgmParse), - 0, - (GInstanceInitFunc) gst_ogm_video_parse_init, - }; - - ogm_video_parse_type = - g_type_register_static (GST_TYPE_OGM_PARSE, - "GstOgmVideoParse", &ogm_video_parse_info, 0); - } - - return ogm_video_parse_type; -} - -static GType -gst_ogm_text_parse_get_type (void) -{ - static GType ogm_text_parse_type = 0; - - if (!ogm_text_parse_type) { - static const GTypeInfo ogm_text_parse_info = { - sizeof (GstOgmParseClass), - (GBaseInitFunc) gst_ogm_text_parse_base_init, - NULL, - NULL, - NULL, - NULL, - sizeof (GstOgmParse), - 0, - (GInstanceInitFunc) gst_ogm_text_parse_init, - }; - - ogm_text_parse_type = - g_type_register_static (GST_TYPE_OGM_PARSE, - "GstOgmTextParse", &ogm_text_parse_info, 0); - } - - return ogm_text_parse_type; -} - -static void -gst_ogm_audio_parse_base_init (GstOgmParseClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstCaps *caps = gst_riff_create_audio_template_caps (); - - gst_element_class_set_details (element_class, &gst_ogm_audio_parse_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_factory_audio)); - audio_src_templ = gst_pad_template_new ("src", - GST_PAD_SRC, GST_PAD_SOMETIMES, caps); - gst_element_class_add_pad_template (element_class, audio_src_templ); -} - -static void -gst_ogm_video_parse_base_init (GstOgmParseClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstCaps *caps = gst_riff_create_video_template_caps (); - - gst_element_class_set_details (element_class, &gst_ogm_video_parse_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_factory_video)); - video_src_templ = gst_pad_template_new ("src", - GST_PAD_SRC, GST_PAD_SOMETIMES, caps); - gst_element_class_add_pad_template (element_class, video_src_templ); -} - -static void -gst_ogm_text_parse_base_init (GstOgmParseClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstCaps *caps = gst_caps_new_simple ("text/plain", NULL, NULL); - - gst_element_class_set_details (element_class, &gst_ogm_text_parse_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_factory_text)); - text_src_templ = gst_pad_template_new ("src", - GST_PAD_SRC, GST_PAD_SOMETIMES, caps); - gst_element_class_add_pad_template (element_class, text_src_templ); -} - -static void -gst_ogm_parse_class_init (GstOgmParseClass * klass) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_ogm_parse_change_state); -} - -static void -gst_ogm_parse_init (GstOgmParse * ogm) -{ - memset (&ogm->hdr, 0, sizeof (ogm->hdr)); - ogm->next_granulepos = 0; - ogm->srcpad = NULL; - ogm->cached_events = NULL; -} - -static void -gst_ogm_audio_parse_init (GstOgmParse * ogm) -{ - ogm->sinkpad = gst_pad_new_from_static_template (&sink_factory_audio, "sink"); - gst_pad_set_query_function (ogm->sinkpad, - GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_query)); - gst_pad_set_chain_function (ogm->sinkpad, - GST_DEBUG_FUNCPTR (gst_ogm_parse_chain)); - gst_pad_set_event_function (ogm->sinkpad, - GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_event)); - gst_element_add_pad (GST_ELEMENT (ogm), ogm->sinkpad); - - ogm->srcpad = NULL; - ogm->srcpadtempl = audio_src_templ; -} - -static void -gst_ogm_video_parse_init (GstOgmParse * ogm) -{ - ogm->sinkpad = gst_pad_new_from_static_template (&sink_factory_video, "sink"); - gst_pad_set_query_function (ogm->sinkpad, - GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_query)); - gst_pad_set_chain_function (ogm->sinkpad, - GST_DEBUG_FUNCPTR (gst_ogm_parse_chain)); - gst_pad_set_event_function (ogm->sinkpad, - GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_event)); - gst_element_add_pad (GST_ELEMENT (ogm), ogm->sinkpad); - - ogm->srcpad = NULL; - ogm->srcpadtempl = video_src_templ; -} - -static void -gst_ogm_text_parse_init (GstOgmParse * ogm) -{ - ogm->sinkpad = gst_pad_new_from_static_template (&sink_factory_text, "sink"); - gst_pad_set_query_type_function (ogm->sinkpad, - gst_ogm_parse_get_sink_querytypes); - gst_pad_set_query_function (ogm->sinkpad, - GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_query)); - gst_pad_set_chain_function (ogm->sinkpad, - GST_DEBUG_FUNCPTR (gst_ogm_parse_chain)); - gst_pad_set_event_function (ogm->sinkpad, - GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_event)); - gst_element_add_pad (GST_ELEMENT (ogm), ogm->sinkpad); - - ogm->srcpad = NULL; - ogm->srcpadtempl = text_src_templ; -} - -static const GstQueryType * -gst_ogm_parse_get_sink_querytypes (GstPad * pad) -{ - static const GstQueryType types[] = { - GST_QUERY_POSITION, - 0 - }; - - return types; -} - -static gboolean -gst_ogm_parse_sink_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = FALSE; - GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad)); - - switch (src_format) { - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_TIME: - switch (ogm->hdr.streamtype[0]) { - case 'a': - *dest_value = GST_SECOND * src_value / ogm->hdr.samples_per_unit; - res = TRUE; - break; - case 'v': - case 't': - *dest_value = (GST_SECOND / 10000000) * - ogm->hdr.time_unit * src_value; - res = TRUE; - break; - default: - break; - } - break; - default: - break; - } - break; - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_DEFAULT: - switch (ogm->hdr.streamtype[0]) { - case 'a': - *dest_value = ogm->hdr.samples_per_unit * src_value / GST_SECOND; - res = TRUE; - break; - case 'v': - case 't': - *dest_value = src_value / - ((GST_SECOND / 10000000) * ogm->hdr.time_unit); - res = TRUE; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - - gst_object_unref (ogm); - return res; -} - -static gboolean -gst_ogm_parse_sink_query (GstPad * pad, GstQuery * query) -{ - GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad)); - GstFormat format; - gboolean res = FALSE; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - { - gint64 val; - - gst_query_parse_position (query, &format, NULL); - - if (format != GST_FORMAT_DEFAULT && format != GST_FORMAT_TIME) - break; - - if ((res = gst_ogm_parse_sink_convert (pad, - GST_FORMAT_DEFAULT, ogm->next_granulepos, &format, &val))) { - /* don't know the total length here.. */ - gst_query_set_position (query, format, val); - } - break; - } - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - /* peel off input */ - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - if ((res = gst_ogm_parse_sink_convert (pad, src_fmt, src_val, - &dest_fmt, &dest_val))) { - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - } - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - - gst_object_unref (ogm); - return res; -} - -static GstFlowReturn -gst_ogm_parse_stream_header (GstOgmParse * ogm, const guint8 * data, guint size) -{ - GstCaps *caps = NULL; - - /* stream header */ - if (size < OGM_STREAM_HEADER_SIZE) - goto buffer_too_small; - - if (!memcmp (data, "video\000\000\000", 8)) { - ogm->hdr.s.video.width = GST_READ_UINT32_LE (&data[44]); - ogm->hdr.s.video.height = GST_READ_UINT32_LE (&data[48]); - } else if (!memcmp (data, "audio\000\000\000", 8)) { - ogm->hdr.s.audio.channels = GST_READ_UINT32_LE (&data[44]); - ogm->hdr.s.audio.blockalign = GST_READ_UINT32_LE (&data[46]); - ogm->hdr.s.audio.avgbytespersec = GST_READ_UINT32_LE (&data[48]); - } else if (!memcmp (data, "text\000\000\000\000", 8)) { - /* nothing here */ - } else { - goto cannot_decode; - } - memcpy (ogm->hdr.streamtype, &data[0], 8); - memcpy (ogm->hdr.subtype, &data[8], 4); - ogm->hdr.subtype[4] = '\0'; - ogm->hdr.size = GST_READ_UINT32_LE (&data[12]); - ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[16]); - ogm->hdr.samples_per_unit = GST_READ_UINT64_LE (&data[24]); - ogm->hdr.default_len = GST_READ_UINT32_LE (&data[32]); - ogm->hdr.buffersize = GST_READ_UINT32_LE (&data[36]); - ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[40]); - - switch (ogm->hdr.streamtype[0]) { - case 'a':{ - guint codec_id = 0; - - if (sscanf (ogm->hdr.subtype, "%04x", &codec_id) != 1) { - GST_WARNING_OBJECT (ogm, "cannot parse subtype %s", ogm->hdr.subtype); - } - - caps = - gst_riff_create_audio_caps (codec_id, NULL, NULL, NULL, NULL, NULL); - - if (caps == NULL) { - GST_WARNING_OBJECT (ogm, "no audio caps for codec %u found", codec_id); - caps = gst_caps_new_simple ("audio/x-ogm-unknown", "codec_id", - G_TYPE_INT, (gint) codec_id, NULL); - } - - gst_caps_set_simple (caps, - "channels", G_TYPE_INT, ogm->hdr.s.audio.channels, - "rate", G_TYPE_INT, ogm->hdr.samples_per_unit, NULL); - - GST_LOG_OBJECT (ogm, "Type: %s, subtype: 0x%04x, channels: %d, " - "samplerate: %d, blockalign: %d, bps: %d, caps = %" GST_PTR_FORMAT, - ogm->hdr.streamtype, codec_id, ogm->hdr.s.audio.channels, - (gint) ogm->hdr.samples_per_unit, ogm->hdr.s.audio.blockalign, - ogm->hdr.s.audio.avgbytespersec, caps); - break; - } - case 'v':{ - guint32 fourcc; - - fourcc = GST_MAKE_FOURCC (ogm->hdr.subtype[0], - ogm->hdr.subtype[1], ogm->hdr.subtype[2], ogm->hdr.subtype[3]); - - caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL); - - if (caps == NULL) { - GST_WARNING_OBJECT (ogm, "could not find video caps for fourcc %" - GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc)); - caps = gst_caps_new_simple ("video/x-ogm-unknown", "fourcc", - GST_TYPE_FOURCC, fourcc, NULL); - break; - } - - GST_LOG_OBJECT (ogm, "Type: %s, subtype: %" GST_FOURCC_FORMAT - ", size: %dx%d, timeunit: %" G_GINT64_FORMAT - " (fps: %lf), s/u: %" G_GINT64_FORMAT ", " - "def.len: %d, bufsize: %d, bps: %d, caps = %" GST_PTR_FORMAT, - ogm->hdr.streamtype, GST_FOURCC_ARGS (fourcc), - ogm->hdr.s.video.width, ogm->hdr.s.video.height, - ogm->hdr.time_unit, 10000000. / ogm->hdr.time_unit, - ogm->hdr.samples_per_unit, ogm->hdr.default_len, - ogm->hdr.buffersize, ogm->hdr.bits_per_sample, caps); - - gst_caps_set_simple (caps, - "width", G_TYPE_INT, ogm->hdr.s.video.width, - "height", G_TYPE_INT, ogm->hdr.s.video.height, - "framerate", GST_TYPE_FRACTION, 10000000, ogm->hdr.time_unit, NULL); - break; - } - case 't':{ - GST_LOG_OBJECT (ogm, "Type: %s, s/u: %" G_GINT64_FORMAT - ", timeunit=%" G_GINT64_FORMAT, - ogm->hdr.streamtype, ogm->hdr.samples_per_unit, ogm->hdr.time_unit); - caps = gst_caps_new_simple ("text/plain", NULL); - break; - } - default: - g_assert_not_reached (); - } - - if (caps == NULL) - goto cannot_decode; - - if (ogm->srcpad) { - GstCaps *current_caps = GST_PAD_CAPS (ogm->srcpad); - - if (current_caps && caps && !gst_caps_is_equal (current_caps, caps)) { - GST_WARNING_OBJECT (ogm, "Already an existing pad %s:%s", - GST_DEBUG_PAD_NAME (ogm->srcpad)); - gst_pad_set_active (ogm->srcpad, FALSE); - gst_element_remove_pad (GST_ELEMENT (ogm), ogm->srcpad); - ogm->srcpad = NULL; - } else { - GST_DEBUG_OBJECT (ogm, "Existing pad has the same caps, do nothing"); - } - } - - if (ogm->srcpad == NULL) { - GList *l, *cached_events; - - ogm->srcpad = gst_pad_new_from_template (ogm->srcpadtempl, "src"); - gst_pad_use_fixed_caps (ogm->srcpad); - gst_pad_set_caps (ogm->srcpad, caps); - gst_pad_set_active (ogm->srcpad, TRUE); - gst_element_add_pad (GST_ELEMENT (ogm), ogm->srcpad); - GST_INFO_OBJECT (ogm, "Added pad %s:%s with caps %" GST_PTR_FORMAT, - GST_DEBUG_PAD_NAME (ogm->srcpad), caps); - - GST_OBJECT_LOCK (ogm); - cached_events = ogm->cached_events; - ogm->cached_events = NULL; - GST_OBJECT_UNLOCK (ogm); - - for (l = cached_events; l; l = l->next) { - GstEvent *event = GST_EVENT_CAST (l->data); - - GST_DEBUG_OBJECT (ogm, "Pushing cached event %" GST_PTR_FORMAT, event); - gst_pad_push_event (ogm->srcpad, event); - } - g_list_free (cached_events); - } - - gst_caps_unref (caps); - - return GST_FLOW_OK; - -/* ERRORS */ -buffer_too_small: - { - GST_ELEMENT_ERROR (ogm, STREAM, WRONG_TYPE, ("Buffer too small"), (NULL)); - return GST_FLOW_ERROR; - } -cannot_decode: - { - GST_ELEMENT_ERROR (ogm, STREAM, DECODE, (NULL), ("unknown ogm format")); - return GST_FLOW_ERROR; - } -} - -static GstFlowReturn -gst_ogm_parse_comment_packet (GstOgmParse * ogm, GstBuffer * buf) -{ - GstFlowReturn ret; - - if (ogm->srcpad == NULL) { - GST_DEBUG ("no source pad"); - return GST_FLOW_WRONG_STATE; - } - - /* if this is not a subtitle stream, push the vorbiscomment packet - * on downstream, the respective decoder will handle it; if it is - * a subtitle stream, we will have to handle the comment ourself */ - if (ogm->hdr.streamtype[0] == 't') { - GstTagList *tags; - - tags = gst_tag_list_from_vorbiscomment_buffer (buf, - (guint8 *) "\003vorbis", 7, NULL); - - if (tags) { - GST_DEBUG_OBJECT (ogm, "tags = %" GST_PTR_FORMAT, tags); - gst_element_found_tags_for_pad (GST_ELEMENT (ogm), ogm->srcpad, tags); - } else { - GST_DEBUG_OBJECT (ogm, "failed to extract tags from vorbis comment"); - } - /* do not push packet downstream, just let parent unref it */ - ret = GST_FLOW_OK; - } else { - buf = gst_buffer_copy (buf); - gst_buffer_set_caps (buf, GST_PAD_CAPS (ogm->srcpad)); - ret = gst_pad_push (ogm->srcpad, buf); - } - - return ret; -} - -static void -gst_ogm_text_parse_strip_trailing_zeroes (GstOgmParse * ogm, GstBuffer * buf) -{ - const guint8 *data; - guint size; - - g_assert (gst_buffer_is_metadata_writable (buf)); - - /* zeroes are not valid UTF-8 characters, so strip them from output */ - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - while (size > 0 && data[size - 1] == '\0') { - --size; - } - - GST_BUFFER_SIZE (buf) = size; -} - -static GstFlowReturn -gst_ogm_parse_data_packet (GstOgmParse * ogm, GstBuffer * buf) -{ - GstFlowReturn ret; - const guint8 *data; - GstBuffer *sbuf; - gboolean keyframe; - guint size, len, n, xsize = 0; - - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - - if ((data[0] & 0x01) != 0) - goto invalid_startcode; - - /* data - push on */ - len = ((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1); - keyframe = (((data[0] & 0x08) >> 3) != 0); - - if ((1 + len) > size) - goto buffer_too_small; - - for (n = len; n > 0; n--) { - xsize = (xsize << 8) | data[n]; - } - - GST_LOG_OBJECT (ogm, "[0x%02x] samples: %d, hdrbytes: %d, datasize: %d", - data[0], xsize, len, size - len - 1); - - sbuf = gst_buffer_create_sub (buf, len + 1, size - len - 1); - - if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) - ogm->next_granulepos = GST_BUFFER_OFFSET_END (buf); - - switch (ogm->hdr.streamtype[0]) { - case 't': - case 'v':{ - GstClockTime ts, next_ts; - guint samples; - - samples = (ogm->hdr.streamtype[0] == 'v') ? 1 : xsize; - - if (!keyframe) { - GST_BUFFER_FLAG_SET (sbuf, GST_BUFFER_FLAG_DELTA_UNIT); - } - - /* shouldn't this be granulepos - samples? (tpm) */ - ts = gst_util_uint64_scale (ogm->next_granulepos, - ogm->hdr.time_unit * GST_SECOND, 10000000); - next_ts = gst_util_uint64_scale (ogm->next_granulepos + samples, - ogm->hdr.time_unit * GST_SECOND, 10000000); - - GST_BUFFER_TIMESTAMP (sbuf) = ts; - GST_BUFFER_DURATION (sbuf) = next_ts - ts; - - ogm->next_granulepos += samples; - - if (ogm->hdr.streamtype[0] == 't') { - gst_ogm_text_parse_strip_trailing_zeroes (ogm, sbuf); - } - break; - } - case 'a':{ - GstClockTime ts, next_ts; - - /* shouldn't this be granulepos - samples? (tpm) */ - ts = gst_util_uint64_scale_int (ogm->next_granulepos, - GST_SECOND, ogm->hdr.samples_per_unit); - next_ts = gst_util_uint64_scale_int (ogm->next_granulepos + xsize, - GST_SECOND, ogm->hdr.samples_per_unit); - - GST_BUFFER_TIMESTAMP (sbuf) = ts; - GST_BUFFER_DURATION (sbuf) = next_ts - ts; - - ogm->next_granulepos += xsize; - break; - } - default: - g_assert_not_reached (); - break; - } - - if (ogm->srcpad) { - gst_buffer_set_caps (sbuf, GST_PAD_CAPS (ogm->srcpad)); - GST_LOG_OBJECT (ogm, "Pushing buffer with ts=%" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sbuf))); - ret = gst_pad_push (ogm->srcpad, sbuf); - if (ret != GST_FLOW_OK) { - GST_DEBUG_OBJECT (ogm, "Flow on %s:%s = %s", - GST_DEBUG_PAD_NAME (ogm->srcpad), gst_flow_get_name (ret)); - } - } else { - ret = GST_FLOW_WRONG_STATE; - } - - return ret; - -/* ERRORS */ -invalid_startcode: - { - GST_ELEMENT_ERROR (ogm, STREAM, DECODE, (NULL), - ("unexpected packet startcode 0x%02x", data[0])); - return GST_FLOW_ERROR; - } -buffer_too_small: - { - GST_ELEMENT_ERROR (ogm, STREAM, DECODE, (NULL), - ("buffer too small, len+1=%u, size=%u", len + 1, size)); - return GST_FLOW_ERROR; - } -} - -static GstFlowReturn -gst_ogm_parse_chain (GstPad * pad, GstBuffer * buf) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstOgmParse *ogm = GST_OGM_PARSE (GST_PAD_PARENT (pad)); - guint8 *data = GST_BUFFER_DATA (buf); - guint size = GST_BUFFER_SIZE (buf); - - if (size < 1) - goto buffer_too_small; - - GST_LOG_OBJECT (ogm, "Packet with start code 0x%02x", data[0]); - - switch (data[0]) { - case 0x01:{ - ret = gst_ogm_parse_stream_header (ogm, data + 1, size - 1); - break; - } - case 0x03:{ - ret = gst_ogm_parse_comment_packet (ogm, buf); - break; - } - default:{ - ret = gst_ogm_parse_data_packet (ogm, buf); - break; - } - } - - gst_buffer_unref (buf); - - if (ret != GST_FLOW_OK) { - GST_DEBUG_OBJECT (ogm, "Flow: %s", gst_flow_get_name (ret)); - } - - return ret; - -/* ERRORS */ -buffer_too_small: - { - GST_ELEMENT_ERROR (ogm, STREAM, DECODE, (NULL), ("buffer too small")); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } -} - -static gboolean -gst_ogm_parse_sink_event (GstPad * pad, GstEvent * event) -{ - GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad)); - gboolean res; - - GST_LOG_OBJECT (ogm, "processing %s event", GST_EVENT_TYPE_NAME (event)); - - GST_OBJECT_LOCK (ogm); - if (ogm->srcpad == NULL) { - ogm->cached_events = g_list_append (ogm->cached_events, event); - GST_OBJECT_UNLOCK (ogm); - res = TRUE; - } else { - GST_OBJECT_UNLOCK (ogm); - res = gst_pad_event_default (pad, event); - } - - gst_object_unref (ogm); - return res; -} - -static GstStateChangeReturn -gst_ogm_parse_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - GstOgmParse *ogm = GST_OGM_PARSE (element); - - ret = parent_class->change_state (element, transition); - if (ret != GST_STATE_CHANGE_SUCCESS) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - if (ogm->srcpad) { - gst_pad_set_active (ogm->srcpad, FALSE); - gst_element_remove_pad (element, ogm->srcpad); - ogm->srcpad = NULL; - } - memset (&ogm->hdr, 0, sizeof (ogm->hdr)); - ogm->next_granulepos = 0; - g_list_foreach (ogm->cached_events, (GFunc) gst_mini_object_unref, NULL); - g_list_free (ogm->cached_events); - ogm->cached_events = NULL; - break; - default: - break; - } - - return ret; -} - -gboolean -gst_ogm_parse_plugin_init (GstPlugin * plugin) -{ - gst_riff_init (); - - GST_DEBUG_CATEGORY_INIT (gst_ogm_parse_debug, "ogmparse", 0, "ogm parser"); - - return gst_element_register (plugin, "ogmaudioparse", GST_RANK_PRIMARY, - GST_TYPE_OGM_AUDIO_PARSE) && - gst_element_register (plugin, "ogmvideoparse", GST_RANK_PRIMARY, - GST_TYPE_OGM_VIDEO_PARSE) && - gst_element_register (plugin, "ogmtextparse", GST_RANK_PRIMARY, - GST_TYPE_OGM_TEXT_PARSE); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/pango/gstclockoverlay.c --- a/gst_plugins_base/ext/pango/gstclockoverlay.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2005> Tim-Philipp Müller - * - * 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. - */ - -/** - * SECTION:element-clockoverlay - * @see_also: #GstTextOverlay, #GstTimeOverlay - * - * - * - * This element overlays the current clock time on top of a video - * stream. You can position the text and configure the font details - * using the properties of the #GstTextOverlay class. By default, the - * time is displayed in the top left corner of the picture, with some - * padding to the left and to the top. - * - * - * Here is a simple pipeline that displays the current time in the top left - * corner of the video picture: - * - * gst-launch -v videotestsrc ! clockoverlay ! xvimagesink - * - * - * - * Here is another pipeline that displays the current time with some leading - * text in the bottom right corner of the video picture, with the background - * of the text being shaded in order to make it more legible on top of a - * bright video background: - * - * gst-launch -v videotestsrc ! clockoverlay halign=right valign=bottom text="Edge City" shaded-background=true ! ffmpegcolorspace ! ximagesink - * - * - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -static const GstElementDetails clock_overlay_details = -GST_ELEMENT_DETAILS ("Clock overlay", - "Filter/Editor/Video", - "Overlays the current clock time on a video stream", - "Tim-Philipp Müller "); - -GST_BOILERPLATE (GstClockOverlay, gst_clock_overlay, GstTextOverlay, - GST_TYPE_TEXT_OVERLAY) - - static void gst_clock_overlay_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &clock_overlay_details); -} - -static gchar * -gst_clock_overlay_render_time (GstClockOverlay * overlay) -{ - struct tm *t; - time_t now; - -#ifdef HAVE_LOCALTIME_R - struct tm dummy; -#endif - - now = time (NULL); - -#ifdef HAVE_LOCALTIME_R - t = localtime_r (&now, &dummy); -#else - /* on win32 this apparently returns a per-thread struct which would be fine */ - t = localtime (&now); -#endif - - if (t == NULL) - return g_strdup ("--:--:--"); - - return g_strdup_printf ("%02u:%02u:%02u", t->tm_hour, t->tm_min, t->tm_sec); -} - -/* Called with lock held */ -static gchar * -gst_clock_overlay_get_text (GstTextOverlay * overlay, GstBuffer * video_frame) -{ - gchar *time_str, *txt, *ret; - - overlay->need_render = TRUE; - - txt = g_strdup (overlay->default_text); - - time_str = gst_clock_overlay_render_time (GST_CLOCK_OVERLAY (overlay)); - if (txt != NULL && *txt != '\0') { - ret = g_strdup_printf ("%s %s", txt, time_str); - } else { - ret = time_str; - time_str = NULL; - } - - g_free (txt); - g_free (time_str); - - return ret; -} - -static void -gst_clock_overlay_class_init (GstClockOverlayClass * klass) -{ - GstTextOverlayClass *gsttextoverlay_class; - - gsttextoverlay_class = (GstTextOverlayClass *) klass; - - gsttextoverlay_class->get_text = gst_clock_overlay_get_text; -} - -static void -gst_clock_overlay_init (GstClockOverlay * overlay, GstClockOverlayClass * klass) -{ - PangoFontDescription *font_description; - GstTextOverlay *textoverlay; - PangoContext *context; - - textoverlay = GST_TEXT_OVERLAY (overlay); - - context = GST_TEXT_OVERLAY_CLASS (klass)->pango_context; - - pango_context_set_language (context, pango_language_from_string ("en_US")); - pango_context_set_base_dir (context, PANGO_DIRECTION_LTR); - - font_description = pango_font_description_new (); - pango_font_description_set_family_static (font_description, "Monospace"); - pango_font_description_set_style (font_description, PANGO_STYLE_NORMAL); - pango_font_description_set_variant (font_description, PANGO_VARIANT_NORMAL); - pango_font_description_set_weight (font_description, PANGO_WEIGHT_NORMAL); - pango_font_description_set_stretch (font_description, PANGO_STRETCH_NORMAL); - pango_font_description_set_size (font_description, 18 * PANGO_SCALE); - pango_context_set_font_description (context, font_description); - pango_font_description_free (font_description); - - textoverlay->valign = GST_TEXT_OVERLAY_VALIGN_TOP; - textoverlay->halign = GST_TEXT_OVERLAY_HALIGN_LEFT; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/pango/gstclockoverlay.h --- a/gst_plugins_base/ext/pango/gstclockoverlay.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2005> Tim-Philipp Müller - * - * 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. - */ - - -#ifndef __GST_CLOCK_OVERLAY_H__ -#define __GST_CLOCK_OVERLAY_H__ - -#include "gsttextoverlay.h" - -G_BEGIN_DECLS - -#define GST_TYPE_CLOCK_OVERLAY \ - (gst_clock_overlay_get_type()) -#define GST_CLOCK_OVERLAY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLOCK_OVERLAY,GstClockOverlay)) -#define GST_CLOCK_OVERLAY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLOCK_OVERLAY,GstClockOverlayClass)) -#define GST_IS_CLOCK_OVERLAY(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLOCK_OVERLAY)) -#define GST_IS_CLOCK_OVERLAY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLOCK_OVERLAY)) - -typedef struct _GstClockOverlay GstClockOverlay; -typedef struct _GstClockOverlayClass GstClockOverlayClass; - -/** - * GstClockOverlay: - * - * Opaque clockoverlay data structure. - */ -struct _GstClockOverlay { - GstTextOverlay textoverlay; -}; - -struct _GstClockOverlayClass { - GstTextOverlayClass parent_class; -}; - -GType gst_clock_overlay_get_type (void); - -G_END_DECLS - -#endif /* __GST_CLOCK_OVERLAY_H__ */ - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/pango/gsttextoverlay.c --- a/gst_plugins_base/ext/pango/gsttextoverlay.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1698 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2003> David Schleef - * Copyright (C) <2006> Julien Moutte - * Copyright (C) <2006> Tim-Philipp Müller - * - * 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. - */ - -/** - * SECTION:element-textoverlay - * @see_also: #GstTextRender, #GstClockOverlay, #GstTimeOverlay, #GstSubParse - * - * - * - * This plugin renders text on top of a video stream. This can be either - * static text or text from buffers received on the text sink pad, e.g. - * as produced by the subparse element. If the text sink pad is not linked, - * the text set via the "text" property will be rendered. If the text sink - * pad is linked, text will be rendered as it is received on that pad, - * honouring and matching the buffer timestamps of both input streams. - * - * - * The text can contain newline characters and text wrapping is enabled by - * default. - * - * - * Here is a simple pipeline that displays a static text in the top left - * corner of the video picture: - * - * gst-launch -v videotestsrc ! textoverlay text="Room A" valign=top halign=left ! xvimagesink - * - * - * - * Here is another pipeline that displays subtitles from an .srt subtitle - * file, centered at the bottom of the picture and with a rectangular shading - * around the text in the background: - * - * gst-launch -v filesrc location=subtitles.srt ! subparse ! txt. videotestsrc ! timeoverlay ! textoverlay name=txt shaded-background=yes ! xvimagesink - * - * If you do not have such a subtitle file, create one looking like this - * in a text editor: - * - * 1 - * 00:00:03,000 --> 00:00:05,000 - * Hello? (3-5s) - * - * 2 - * 00:00:08,000 --> 00:00:13,000 - * Yes, this is a subtitle. Don't - * you like it? (8-13s) - * - * 3 - * 00:00:18,826 --> 00:01:02,886 - * Uh? What are you talking about? - * I don't understand (18-62s) - * - * - * - */ - -/* FIXME: alloc segment as part of instance struct */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "gsttextoverlay.h" -#include "gsttimeoverlay.h" -#include "gstclockoverlay.h" -#include "gsttextrender.h" - -/* FIXME: - * - use proper strides and offset for I420 - * - if text is wider than the video picture, it does not get - * clipped properly during blitting (if wrapping is disabled) - * - make 'shading_value' a property (or enum: light/normal/dark/verydark)? - */ - -GST_DEBUG_CATEGORY (pango_debug); -#define GST_CAT_DEFAULT pango_debug - -static const GstElementDetails text_overlay_details = -GST_ELEMENT_DETAILS ("Text overlay", - "Filter/Editor/Video", - "Adds text strings on top of a video buffer", - "David Schleef "); - - -#define DEFAULT_PROP_TEXT "" -#define DEFAULT_PROP_SHADING FALSE -#define DEFAULT_PROP_VALIGNMENT GST_TEXT_OVERLAY_VALIGN_BASELINE -#define DEFAULT_PROP_HALIGNMENT GST_TEXT_OVERLAY_HALIGN_CENTER -#define DEFAULT_PROP_VALIGN "baseline" -#define DEFAULT_PROP_HALIGN "center" -#define DEFAULT_PROP_XPAD 25 -#define DEFAULT_PROP_YPAD 25 -#define DEFAULT_PROP_DELTAX 0 -#define DEFAULT_PROP_DELTAY 0 -#define DEFAULT_PROP_WRAP_MODE GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR -#define DEFAULT_PROP_FONT_DESC "" -#define DEFAULT_PROP_SILENT FALSE -#define DEFAULT_PROP_LINE_ALIGNMENT GST_TEXT_OVERLAY_LINE_ALIGN_CENTER - -/* make a property of me */ -#define DEFAULT_SHADING_VALUE -80 - -enum -{ - PROP_0, - PROP_TEXT, - PROP_SHADING, - PROP_VALIGN, /* deprecated */ - PROP_HALIGN, /* deprecated */ - PROP_HALIGNMENT, - PROP_VALIGNMENT, - PROP_XPAD, - PROP_YPAD, - PROP_DELTAX, - PROP_DELTAY, - PROP_WRAP_MODE, - PROP_FONT_DESC, - PROP_SILENT, - PROP_LINE_ALIGNMENT -}; - - -static GstStaticPadTemplate src_template_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")) - ); - -static GstStaticPadTemplate video_sink_template_factory = -GST_STATIC_PAD_TEMPLATE ("video_sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")) - ); - -static GstStaticPadTemplate text_sink_template_factory = - GST_STATIC_PAD_TEMPLATE ("text_sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("text/x-pango-markup; text/plain") - ); - - -#define GST_TYPE_TEXT_OVERLAY_VALIGN (gst_text_overlay_valign_get_type()) -static GType -gst_text_overlay_valign_get_type (void) -{ - static GType text_overlay_valign_type = 0; - static const GEnumValue text_overlay_valign[] = { - {GST_TEXT_OVERLAY_VALIGN_BASELINE, "baseline", "baseline"}, - {GST_TEXT_OVERLAY_VALIGN_BOTTOM, "bottom", "bottom"}, - {GST_TEXT_OVERLAY_VALIGN_TOP, "top", "top"}, - {0, NULL, NULL}, - }; - - if (!text_overlay_valign_type) { - text_overlay_valign_type = - g_enum_register_static ("GstTextOverlayVAlign", text_overlay_valign); - } - return text_overlay_valign_type; -} - -#define GST_TYPE_TEXT_OVERLAY_HALIGN (gst_text_overlay_halign_get_type()) -static GType -gst_text_overlay_halign_get_type (void) -{ - static GType text_overlay_halign_type = 0; - static const GEnumValue text_overlay_halign[] = { - {GST_TEXT_OVERLAY_HALIGN_LEFT, "left", "left"}, - {GST_TEXT_OVERLAY_HALIGN_CENTER, "center", "center"}, - {GST_TEXT_OVERLAY_HALIGN_RIGHT, "right", "right"}, - {0, NULL, NULL}, - }; - - if (!text_overlay_halign_type) { - text_overlay_halign_type = - g_enum_register_static ("GstTextOverlayHAlign", text_overlay_halign); - } - return text_overlay_halign_type; -} - - -#define GST_TYPE_TEXT_OVERLAY_WRAP_MODE (gst_text_overlay_wrap_mode_get_type()) -static GType -gst_text_overlay_wrap_mode_get_type (void) -{ - static GType text_overlay_wrap_mode_type = 0; - static const GEnumValue text_overlay_wrap_mode[] = { - {GST_TEXT_OVERLAY_WRAP_MODE_NONE, "none", "none"}, - {GST_TEXT_OVERLAY_WRAP_MODE_WORD, "word", "word"}, - {GST_TEXT_OVERLAY_WRAP_MODE_CHAR, "char", "char"}, - {GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR, "wordchar", "wordchar"}, - {0, NULL, NULL}, - }; - - if (!text_overlay_wrap_mode_type) { - text_overlay_wrap_mode_type = - g_enum_register_static ("GstTextOverlayWrapMode", - text_overlay_wrap_mode); - } - return text_overlay_wrap_mode_type; -} - -#define GST_TYPE_TEXT_OVERLAY_LINE_ALIGN (gst_text_overlay_line_align_get_type()) -static GType -gst_text_overlay_line_align_get_type (void) -{ - static GType text_overlay_line_align_type = 0; - static const GEnumValue text_overlay_line_align[] = { - {GST_TEXT_OVERLAY_LINE_ALIGN_LEFT, "left", "left"}, - {GST_TEXT_OVERLAY_LINE_ALIGN_CENTER, "center", "center"}, - {GST_TEXT_OVERLAY_LINE_ALIGN_RIGHT, "right", "right"}, - {0, NULL, NULL} - }; - - if (!text_overlay_line_align_type) { - text_overlay_line_align_type = - g_enum_register_static ("GstTextOverlayLineAlign", - text_overlay_line_align); - } - return text_overlay_line_align_type; -} - -/* These macros are adapted from videotestsrc.c */ -#define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width)) -#define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2) -#define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2) - -#define I420_Y_OFFSET(w,h) (0) -#define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h))) -#define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2)) - -#define I420_SIZE(w,h) (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2)) - -#define GST_TEXT_OVERLAY_GET_COND(ov) (((GstTextOverlay *)ov)->cond) -#define GST_TEXT_OVERLAY_WAIT(ov) (g_cond_wait (GST_TEXT_OVERLAY_GET_COND (ov), GST_OBJECT_GET_LOCK (ov))) -#define GST_TEXT_OVERLAY_SIGNAL(ov) (g_cond_signal (GST_TEXT_OVERLAY_GET_COND (ov))) -#define GST_TEXT_OVERLAY_BROADCAST(ov)(g_cond_broadcast (GST_TEXT_OVERLAY_GET_COND (ov))) - -static GstStateChangeReturn gst_text_overlay_change_state (GstElement * element, - GstStateChange transition); - -static GstCaps *gst_text_overlay_getcaps (GstPad * pad); -static gboolean gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps); -static gboolean gst_text_overlay_setcaps_txt (GstPad * pad, GstCaps * caps); -static gboolean gst_text_overlay_src_event (GstPad * pad, GstEvent * event); - -static gboolean gst_text_overlay_video_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_text_overlay_video_chain (GstPad * pad, - GstBuffer * buffer); - -static gboolean gst_text_overlay_text_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_text_overlay_text_chain (GstPad * pad, - GstBuffer * buffer); -static GstPadLinkReturn gst_text_overlay_text_pad_link (GstPad * pad, - GstPad * peer); -static void gst_text_overlay_text_pad_unlink (GstPad * pad); -static void gst_text_overlay_pop_text (GstTextOverlay * overlay); - -static void gst_text_overlay_finalize (GObject * object); -static void gst_text_overlay_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_text_overlay_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -GST_BOILERPLATE (GstTextOverlay, gst_text_overlay, GstElement, GST_TYPE_ELEMENT) - - static void gst_text_overlay_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_template_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&video_sink_template_factory)); - - /* ugh */ - if (!GST_IS_TIME_OVERLAY_CLASS (g_class) && - !GST_IS_CLOCK_OVERLAY_CLASS (g_class)) { - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&text_sink_template_factory)); - } - - gst_element_class_set_details (element_class, &text_overlay_details); -} - -static gchar * -gst_text_overlay_get_text (GstTextOverlay * overlay, GstBuffer * video_frame) -{ - return g_strdup (overlay->default_text); -} - -static void -gst_text_overlay_class_init (GstTextOverlayClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - gobject_class->finalize = gst_text_overlay_finalize; - gobject_class->set_property = gst_text_overlay_set_property; - gobject_class->get_property = gst_text_overlay_get_property; - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_text_overlay_change_state); - - klass->get_text = gst_text_overlay_get_text; - klass->pango_context = pango_ft2_get_context (72, 72); - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TEXT, - g_param_spec_string ("text", "text", - "Text to be display.", DEFAULT_PROP_TEXT, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SHADING, - g_param_spec_boolean ("shaded-background", "shaded background", - "Whether to shade the background under the text area", - DEFAULT_PROP_SHADING, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VALIGNMENT, - g_param_spec_enum ("valignment", "vertical alignment", - "Vertical alignment of the text", - GST_TYPE_TEXT_OVERLAY_VALIGN, DEFAULT_PROP_VALIGNMENT, - G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HALIGNMENT, - g_param_spec_enum ("halignment", "horizontal alignment", - "Horizontal alignment of the text", GST_TYPE_TEXT_OVERLAY_HALIGN, - DEFAULT_PROP_HALIGNMENT, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VALIGN, - g_param_spec_string ("valign", "vertical alignment", - "Vertical alignment of the text (deprecated; use valignment)", - DEFAULT_PROP_VALIGN, G_PARAM_WRITABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HALIGN, - g_param_spec_string ("halign", "horizontal alignment", - "Horizontal alignment of the text (deprecated; use halignment)", - DEFAULT_PROP_HALIGN, G_PARAM_WRITABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_XPAD, - g_param_spec_int ("xpad", "horizontal paddding", - "Horizontal paddding when using left/right alignment", 0, G_MAXINT, - DEFAULT_PROP_XPAD, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_YPAD, - g_param_spec_int ("ypad", "vertical padding", - "Vertical padding when using top/bottom alignment", 0, G_MAXINT, - DEFAULT_PROP_YPAD, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELTAX, - g_param_spec_int ("deltax", "X position modifier", - "Shift X position to the left or to the right. Unit is pixels.", - G_MININT, G_MAXINT, DEFAULT_PROP_DELTAX, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELTAY, - g_param_spec_int ("deltay", "Y position modifier", - "Shift Y position up or down. Unit is pixels.", G_MININT, G_MAXINT, - DEFAULT_PROP_DELTAY, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WRAP_MODE, - g_param_spec_enum ("wrap-mode", "wrap mode", - "Whether to wrap the text and if so how.", - GST_TYPE_TEXT_OVERLAY_WRAP_MODE, DEFAULT_PROP_WRAP_MODE, - G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FONT_DESC, - g_param_spec_string ("font-desc", "font description", - "Pango font description of font to be used for rendering. " - "See documentation of pango_font_description_from_string " - "for syntax.", DEFAULT_PROP_FONT_DESC, G_PARAM_WRITABLE)); - /** - * GstTextOverlay:line-alignment - * - * Alignment of text lines relative to each other (for multi-line text) - * - * Since: 0.10.15 - **/ - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LINE_ALIGNMENT, - g_param_spec_enum ("line-alignment", "line alignment", - "Alignment of text lines relative to each other.", - GST_TYPE_TEXT_OVERLAY_LINE_ALIGN, DEFAULT_PROP_LINE_ALIGNMENT, - G_PARAM_READWRITE)); - /** - * GstTextOverlay:silent - * - * If set, no text is rendered. Useful to switch off text rendering - * temporarily without removing the textoverlay element from the pipeline. - * - * Since: 0.10.15 - **/ - /* FIXME 0.11: rename to "visible" or "text-visible" or "render-text" */ - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT, - g_param_spec_boolean ("silent", "silent", - "Whether to render the text string", - DEFAULT_PROP_SILENT, G_PARAM_READWRITE)); -} - -static void -gst_text_overlay_finalize (GObject * object) -{ - GstTextOverlay *overlay = GST_TEXT_OVERLAY (object); - - g_free (overlay->default_text); - g_free (overlay->bitmap.buffer); - - if (overlay->layout) { - g_object_unref (overlay->layout); - overlay->layout = NULL; - } - - if (overlay->segment) { - gst_segment_free (overlay->segment); - overlay->segment = NULL; - } - - if (overlay->text_buffer) { - gst_buffer_unref (overlay->text_buffer); - overlay->text_buffer = NULL; - } - - if (overlay->cond) { - g_cond_free (overlay->cond); - overlay->cond = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_text_overlay_init (GstTextOverlay * overlay, GstTextOverlayClass * klass) -{ - GstPadTemplate *template; - - /* video sink */ - template = gst_static_pad_template_get (&video_sink_template_factory); - overlay->video_sinkpad = gst_pad_new_from_template (template, "video_sink"); - gst_object_unref (template); - gst_pad_set_getcaps_function (overlay->video_sinkpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_getcaps)); - gst_pad_set_setcaps_function (overlay->video_sinkpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_setcaps)); - gst_pad_set_event_function (overlay->video_sinkpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_video_event)); - gst_pad_set_chain_function (overlay->video_sinkpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_video_chain)); - gst_element_add_pad (GST_ELEMENT (overlay), overlay->video_sinkpad); - - if (!GST_IS_TIME_OVERLAY_CLASS (klass) && !GST_IS_CLOCK_OVERLAY_CLASS (klass)) { - /* text sink */ - template = gst_static_pad_template_get (&text_sink_template_factory); - overlay->text_sinkpad = gst_pad_new_from_template (template, "text_sink"); - gst_object_unref (template); - gst_pad_set_setcaps_function (overlay->text_sinkpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_setcaps_txt)); - gst_pad_set_event_function (overlay->text_sinkpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_text_event)); - gst_pad_set_chain_function (overlay->text_sinkpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_text_chain)); - gst_pad_set_link_function (overlay->text_sinkpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_text_pad_link)); - gst_pad_set_unlink_function (overlay->text_sinkpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_text_pad_unlink)); - gst_element_add_pad (GST_ELEMENT (overlay), overlay->text_sinkpad); - } - - /* (video) source */ - template = gst_static_pad_template_get (&src_template_factory); - overlay->srcpad = gst_pad_new_from_template (template, "src"); - gst_object_unref (template); - gst_pad_set_getcaps_function (overlay->srcpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_getcaps)); - gst_pad_set_event_function (overlay->srcpad, - GST_DEBUG_FUNCPTR (gst_text_overlay_src_event)); - gst_element_add_pad (GST_ELEMENT (overlay), overlay->srcpad); - - overlay->line_align = DEFAULT_PROP_LINE_ALIGNMENT; - overlay->layout = - pango_layout_new (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_context); - pango_layout_set_alignment (overlay->layout, - (PangoAlignment) overlay->line_align); - memset (&overlay->bitmap, 0, sizeof (overlay->bitmap)); - - overlay->halign = DEFAULT_PROP_HALIGNMENT; - overlay->valign = DEFAULT_PROP_VALIGNMENT; - overlay->xpad = DEFAULT_PROP_XPAD; - overlay->ypad = DEFAULT_PROP_YPAD; - overlay->deltax = DEFAULT_PROP_DELTAX; - overlay->deltay = DEFAULT_PROP_DELTAY; - - overlay->wrap_mode = DEFAULT_PROP_WRAP_MODE; - - overlay->want_shading = DEFAULT_PROP_SHADING; - overlay->shading_value = DEFAULT_SHADING_VALUE; - overlay->silent = DEFAULT_PROP_SILENT; - - overlay->default_text = g_strdup (DEFAULT_PROP_TEXT); - overlay->need_render = TRUE; - - overlay->fps_n = 0; - overlay->fps_d = 1; - - overlay->text_buffer = NULL; - overlay->text_linked = FALSE; - overlay->video_flushing = FALSE; - overlay->text_flushing = FALSE; - overlay->text_eos = FALSE; - overlay->cond = g_cond_new (); - overlay->segment = gst_segment_new (); - if (overlay->segment) { - gst_segment_init (overlay->segment, GST_FORMAT_TIME); - } else { - GST_WARNING_OBJECT (overlay, "segment creation failed"); - g_assert_not_reached (); - } -} - -static void -gst_text_overlay_update_wrap_mode (GstTextOverlay * overlay) -{ - if (overlay->wrap_mode == GST_TEXT_OVERLAY_WRAP_MODE_NONE) { - GST_DEBUG_OBJECT (overlay, "Set wrap mode NONE"); - pango_layout_set_width (overlay->layout, -1); - } else { - GST_DEBUG_OBJECT (overlay, "Set layout width %d", overlay->width); - GST_DEBUG_OBJECT (overlay, "Set wrap mode %d", overlay->wrap_mode); - pango_layout_set_width (overlay->layout, overlay->width * PANGO_SCALE); - pango_layout_set_wrap (overlay->layout, (PangoWrapMode) overlay->wrap_mode); - } -} - -static gboolean -gst_text_overlay_setcaps_txt (GstPad * pad, GstCaps * caps) -{ - GstTextOverlay *overlay; - GstStructure *structure; - - overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad)); - - structure = gst_caps_get_structure (caps, 0); - overlay->have_pango_markup = - gst_structure_has_name (structure, "text/x-pango-markup"); - - gst_object_unref (overlay); - - return TRUE; -} - -/* FIXME: upstream nego (e.g. when the video window is resized) */ - -static gboolean -gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps) -{ - GstTextOverlay *overlay; - GstStructure *structure; - gboolean ret = FALSE; - const GValue *fps; - - if (!GST_PAD_IS_SINK (pad)) - return TRUE; - - g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); - - overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad)); - - overlay->width = 0; - overlay->height = 0; - structure = gst_caps_get_structure (caps, 0); - fps = gst_structure_get_value (structure, "framerate"); - - if (gst_structure_get_int (structure, "width", &overlay->width) && - gst_structure_get_int (structure, "height", &overlay->height) && - fps != NULL) { - ret = gst_pad_set_caps (overlay->srcpad, caps); - } - - overlay->fps_n = gst_value_get_fraction_numerator (fps); - overlay->fps_d = gst_value_get_fraction_denominator (fps); - - if (ret) { - GST_OBJECT_LOCK (overlay); - gst_text_overlay_update_wrap_mode (overlay); - GST_OBJECT_UNLOCK (overlay); - } - - gst_object_unref (overlay); - - return ret; -} - -static void -gst_text_overlay_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstTextOverlay *overlay = GST_TEXT_OVERLAY (object); - - GST_OBJECT_LOCK (overlay); - switch (prop_id) { - case PROP_TEXT: - g_free (overlay->default_text); - overlay->default_text = g_value_dup_string (value); - overlay->need_render = TRUE; - break; - case PROP_SHADING: - overlay->want_shading = g_value_get_boolean (value); - break; - case PROP_XPAD: - overlay->xpad = g_value_get_int (value); - break; - case PROP_YPAD: - overlay->ypad = g_value_get_int (value); - break; - case PROP_DELTAX: - overlay->deltax = g_value_get_int (value); - break; - case PROP_DELTAY: - overlay->deltay = g_value_get_int (value); - break; - case PROP_HALIGN:{ - const gchar *s = g_value_get_string (value); - - if (s && g_ascii_strcasecmp (s, "left") == 0) - overlay->halign = GST_TEXT_OVERLAY_HALIGN_LEFT; - else if (s && g_ascii_strcasecmp (s, "center") == 0) - overlay->halign = GST_TEXT_OVERLAY_HALIGN_CENTER; - else if (s && g_ascii_strcasecmp (s, "right") == 0) - overlay->halign = GST_TEXT_OVERLAY_HALIGN_RIGHT; - else - g_warning ("Invalid value '%s' for textoverlay property 'halign'", - GST_STR_NULL (s)); - break; - } - case PROP_VALIGN:{ - const gchar *s = g_value_get_string (value); - - if (s && g_ascii_strcasecmp (s, "baseline") == 0) - overlay->valign = GST_TEXT_OVERLAY_VALIGN_BASELINE; - else if (s && g_ascii_strcasecmp (s, "bottom") == 0) - overlay->valign = GST_TEXT_OVERLAY_VALIGN_BOTTOM; - else if (s && g_ascii_strcasecmp (s, "top") == 0) - overlay->valign = GST_TEXT_OVERLAY_VALIGN_TOP; - else - g_warning ("Invalid value '%s' for textoverlay property 'valign'", - GST_STR_NULL (s)); - break; - } - case PROP_VALIGNMENT: - overlay->valign = g_value_get_enum (value); - break; - case PROP_HALIGNMENT: - overlay->halign = g_value_get_enum (value); - break; - case PROP_WRAP_MODE: - overlay->wrap_mode = g_value_get_enum (value); - gst_text_overlay_update_wrap_mode (overlay); - break; - case PROP_FONT_DESC: - { - PangoFontDescription *desc; - const gchar *fontdesc_str; - - fontdesc_str = g_value_get_string (value); - desc = pango_font_description_from_string (fontdesc_str); - if (desc) { - GST_LOG_OBJECT (overlay, "font description set: %s", fontdesc_str); - pango_layout_set_font_description (overlay->layout, desc); - pango_font_description_free (desc); - } else { - GST_WARNING_OBJECT (overlay, "font description parse failed: %s", - fontdesc_str); - } - break; - } - case PROP_SILENT: - overlay->silent = g_value_get_boolean (value); - break; - case PROP_LINE_ALIGNMENT: - overlay->line_align = g_value_get_enum (value); - pango_layout_set_alignment (overlay->layout, - (PangoAlignment) overlay->line_align); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - overlay->need_render = TRUE; - GST_OBJECT_UNLOCK (overlay); -} - -static void -gst_text_overlay_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstTextOverlay *overlay = GST_TEXT_OVERLAY (object); - - GST_OBJECT_LOCK (overlay); - switch (prop_id) { - case PROP_TEXT: - g_value_set_string (value, overlay->default_text); - break; - case PROP_SHADING: - g_value_set_boolean (value, overlay->want_shading); - break; - case PROP_XPAD: - g_value_set_int (value, overlay->xpad); - break; - case PROP_YPAD: - g_value_set_int (value, overlay->ypad); - break; - case PROP_DELTAX: - g_value_set_int (value, overlay->deltax); - break; - case PROP_DELTAY: - g_value_set_int (value, overlay->deltay); - break; - case PROP_VALIGNMENT: - g_value_set_enum (value, overlay->valign); - break; - case PROP_HALIGNMENT: - g_value_set_enum (value, overlay->halign); - break; - case PROP_WRAP_MODE: - g_value_set_enum (value, overlay->wrap_mode); - break; - case PROP_SILENT: - g_value_set_boolean (value, overlay->silent); - break; - case PROP_LINE_ALIGNMENT: - g_value_set_enum (value, overlay->line_align); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - overlay->need_render = TRUE; - GST_OBJECT_UNLOCK (overlay); -} - -static gboolean -gst_text_overlay_src_event (GstPad * pad, GstEvent * event) -{ - gboolean ret = FALSE; - GstTextOverlay *overlay = NULL; - - overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - /* We don't handle seek if we have not text pad */ - if (!overlay->text_linked) { - ret = gst_pad_push_event (overlay->video_sinkpad, event); - goto beach; - } - - GST_DEBUG_OBJECT (overlay, "seek received, driving from here"); - - /* Flush downstream, FIXME, only for flushing seek */ - gst_pad_push_event (overlay->srcpad, gst_event_new_flush_start ()); - - /* Mark ourself as flushing, unblock chains */ - GST_OBJECT_LOCK (overlay); - overlay->video_flushing = TRUE; - overlay->text_flushing = TRUE; - gst_text_overlay_pop_text (overlay); - GST_OBJECT_UNLOCK (overlay); - - /* Seek on each sink pad */ - gst_event_ref (event); - ret = gst_pad_push_event (overlay->video_sinkpad, event); - if (ret) { - ret = gst_pad_push_event (overlay->text_sinkpad, event); - } else { - gst_event_unref (event); - } - break; - default: - if (overlay->text_linked) { - gst_event_ref (event); - ret = gst_pad_push_event (overlay->video_sinkpad, event); - gst_pad_push_event (overlay->text_sinkpad, event); - } else { - ret = gst_pad_push_event (overlay->video_sinkpad, event); - } - break; - } - -beach: - gst_object_unref (overlay); - - return ret; -} - -static GstCaps * -gst_text_overlay_getcaps (GstPad * pad) -{ - GstTextOverlay *overlay; - GstPad *otherpad; - GstCaps *caps; - - overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad)); - - if (pad == overlay->srcpad) - otherpad = overlay->video_sinkpad; - else - otherpad = overlay->srcpad; - - /* we can do what the peer can */ - caps = gst_pad_peer_get_caps (otherpad); - if (caps) { - GstCaps *temp; - const GstCaps *templ; - - GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps); - - /* filtered against our padtemplate */ - templ = gst_pad_get_pad_template_caps (otherpad); - GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ); - temp = gst_caps_intersect (caps, templ); - GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp); - gst_caps_unref (caps); - /* this is what we can do */ - caps = temp; - } else { - /* no peer, our padtemplate is enough then */ - caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); - } - - GST_DEBUG_OBJECT (overlay, "returning %" GST_PTR_FORMAT, caps); - - gst_object_unref (overlay); - - return caps; -} - -#define BOX_XPAD 6 -#define BOX_YPAD 6 - -static inline void -gst_text_overlay_shade_y (GstTextOverlay * overlay, guchar * dest, - guint dest_stride, gint x0, gint x1, gint y0, gint y1) -{ - gint i, j; - - x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width); - x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width); - - y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height); - y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height); - - for (i = y0; i < y1; ++i) { - for (j = x0; j < x1; ++j) { - gint y = dest[(i * dest_stride) + j] + overlay->shading_value; - - dest[(i * dest_stride) + j] = CLAMP (y, 0, 255); - } - } -} - -/* FIXME: - * - use proper strides and offset for I420 - * - don't draw over the edge of the picture (try a longer - * text with a huge font size) - */ - -static inline void -gst_text_overlay_blit_yuv420 (GstTextOverlay * overlay, FT_Bitmap * bitmap, - guint8 * yuv_pixels, gint x0, gint y0) -{ - int y; /* text bitmap coordinates */ - int x1, y1; /* video buffer coordinates */ - int bit_rowinc, uv_rowinc; - guint8 *p, *bitp, *u_p; - int video_width, video_height; - int bitmap_x0 = 0; //x0 < 1 ? -(x0 - 1) : 1; /* 1 pixel border */ - int bitmap_y0 = y0 < 1 ? -(y0 - 1) : 1; /* 1 pixel border */ - int bitmap_width = bitmap->width - bitmap_x0; - int bitmap_height = bitmap->rows - bitmap_y0; - int u_plane_size; - int skip_y, skip_x; - guint8 v; - - video_width = I420_Y_ROWSTRIDE (overlay->width); - video_height = overlay->height; - -/* - if (x0 < 0 && abs (x0) < bitmap_width) { - bitmap_x0 = abs (x0); - x0 = 0; - } -*/ - - if (x0 + bitmap_x0 + bitmap_width > overlay->width - 1) /* 1 pixel border */ - bitmap_width -= x0 + bitmap_x0 + bitmap_width - overlay->width + 1; - if (y0 + bitmap_y0 + bitmap_height > video_height - 1) /* 1 pixel border */ - bitmap_height -= y0 + bitmap_y0 + bitmap_height - video_height + 1; - - uv_rowinc = video_width / 2 - bitmap_width / 2; - bit_rowinc = bitmap->pitch - bitmap_width; - u_plane_size = (video_width / 2) * (video_height / 2); - - y1 = y0 + bitmap_y0; - x1 = x0 + bitmap_x0; - bitp = bitmap->buffer + bitmap->pitch * bitmap_y0 + bitmap_x0; - for (y = bitmap_y0; y < bitmap_y0 + bitmap_height; y++) { - int n; - - p = yuv_pixels + (y + y0) * I420_Y_ROWSTRIDE (overlay->width) + x1; - for (n = bitmap_width; n > 0; --n) { - v = *bitp; - if (v) { - p[-1] = CLAMP (p[-1] - v, 0, 255); - p[1] = CLAMP (p[1] - v, 0, 255); - p[-video_width] = CLAMP (p[-video_width] - v, 0, 255); - p[video_width] = CLAMP (p[video_width] - v, 0, 255); - } - p++; - bitp++; - } - bitp += bit_rowinc; - } - - y = bitmap_y0; - y1 = y0 + bitmap_y0; - x1 = x0 + bitmap_x0; - bitp = bitmap->buffer + bitmap->pitch * bitmap_y0 + bitmap_x0; - p = yuv_pixels + video_width * y1 + x1; - u_p = - yuv_pixels + video_width * video_height + (video_width >> 1) * (y1 >> 1) + - (x1 >> 1); - skip_y = 0; - skip_x = 0; - - for (; y < bitmap_y0 + bitmap_height; y++) { - int n; - - x1 = x0 + bitmap_x0; - skip_x = 0; - for (n = bitmap_width; n > 0; --n) { - v = *bitp; - if (v) { - *p = v; - if (!skip_y) { - u_p[0] = u_p[u_plane_size] = 0x80; - } - } - if (!skip_y) { - skip_x = !skip_x; - if (!skip_x) - u_p++; - } - p++; - bitp++; - } - /*if (!skip_x && !skip_y) u_p--; */ - p += I420_Y_ROWSTRIDE (overlay->width) - bitmap_width; - bitp += bit_rowinc; - skip_y = !skip_y; - u_p += skip_y ? uv_rowinc : 0; - } -} - -static void -gst_text_overlay_resize_bitmap (GstTextOverlay * overlay, gint width, - gint height) -{ - FT_Bitmap *bitmap = &overlay->bitmap; - int pitch = (width | 3) + 1; - int size = pitch * height; - - /* no need to keep reallocating; just keep the maximum size so far */ - if (size <= overlay->bitmap_buffer_size) { - bitmap->rows = height; - bitmap->width = width; - bitmap->pitch = pitch; - memset (bitmap->buffer, 0, overlay->bitmap_buffer_size); - return; - } - if (!bitmap->buffer) { - /* initialize */ - bitmap->pixel_mode = ft_pixel_mode_grays; - bitmap->num_grays = 256; - } - overlay->bitmap_buffer_size = size; - bitmap->buffer = g_realloc (bitmap->buffer, size); - memset (bitmap->buffer, 0, size); - bitmap->rows = height; - bitmap->width = width; - bitmap->pitch = pitch; -} - -static void -gst_text_overlay_render_text (GstTextOverlay * overlay, - const gchar * text, gint textlen) -{ - PangoRectangle ink_rect, logical_rect; - gchar *string; - - if (!overlay->need_render) { - GST_DEBUG ("Using previously rendered text."); - return; - } - - /* -1 is the whole string */ - if (text != NULL && textlen < 0) { - textlen = strlen (text); - } - - if (text != NULL) { - string = g_strndup (text, textlen); - } else { /* empty string */ - string = g_strdup (" "); - } - g_strdelimit (string, "\r\t", ' '); - textlen = strlen (string); - - /* FIXME: should we check for UTF-8 here? */ - - GST_DEBUG ("Rendering '%s'", string); - pango_layout_set_markup (overlay->layout, string, textlen); - - pango_layout_get_pixel_extents (overlay->layout, &ink_rect, &logical_rect); - gst_text_overlay_resize_bitmap (overlay, ink_rect.width, - ink_rect.height + ink_rect.y); - pango_ft2_render_layout (&overlay->bitmap, overlay->layout, -ink_rect.x, 0); - overlay->baseline_y = ink_rect.y; - - g_free (string); - - overlay->need_render = FALSE; -} - -static GstFlowReturn -gst_text_overlay_push_frame (GstTextOverlay * overlay, GstBuffer * video_frame) -{ - gint xpos, ypos; - - video_frame = gst_buffer_make_writable (video_frame); - - switch (overlay->halign) { - case GST_TEXT_OVERLAY_HALIGN_LEFT: - xpos = overlay->xpad; - break; - case GST_TEXT_OVERLAY_HALIGN_CENTER: - xpos = (overlay->width - overlay->bitmap.width) / 2; - break; - case GST_TEXT_OVERLAY_HALIGN_RIGHT: - xpos = overlay->width - overlay->bitmap.width - overlay->xpad; - break; - default: - xpos = 0; - } - xpos += overlay->deltax; - - - switch (overlay->valign) { - case GST_TEXT_OVERLAY_VALIGN_BOTTOM: - ypos = overlay->height - overlay->bitmap.rows - overlay->ypad; - break; - case GST_TEXT_OVERLAY_VALIGN_BASELINE: - ypos = overlay->height - (overlay->bitmap.rows + overlay->ypad); - break; - case GST_TEXT_OVERLAY_VALIGN_TOP: - ypos = overlay->ypad; - break; - default: - ypos = overlay->ypad; - break; - } - ypos += overlay->deltay; - - /* shaded background box */ - if (overlay->want_shading) { - gst_text_overlay_shade_y (overlay, - GST_BUFFER_DATA (video_frame), - I420_Y_ROWSTRIDE (overlay->width), - xpos, xpos + overlay->bitmap.width, ypos, ypos + overlay->bitmap.rows); - } - - - if (overlay->bitmap.buffer) { - gst_text_overlay_blit_yuv420 (overlay, &overlay->bitmap, - GST_BUFFER_DATA (video_frame), xpos, ypos); - } - - return gst_pad_push (overlay->srcpad, video_frame); -} - -static GstPadLinkReturn -gst_text_overlay_text_pad_link (GstPad * pad, GstPad * peer) -{ - GstTextOverlay *overlay; - - overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad)); - - GST_DEBUG_OBJECT (overlay, "Text pad linked"); - - overlay->text_linked = TRUE; - - gst_object_unref (overlay); - - return GST_PAD_LINK_OK; -} - -static void -gst_text_overlay_text_pad_unlink (GstPad * pad) -{ - GstTextOverlay *overlay; - - /* don't use gst_pad_get_parent() here, will deadlock */ - overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad)); - - GST_DEBUG_OBJECT (overlay, "Text pad unlinked"); - - overlay->text_linked = FALSE; - - gst_segment_init (&overlay->text_segment, GST_FORMAT_UNDEFINED); -} - -static gboolean -gst_text_overlay_text_event (GstPad * pad, GstEvent * event) -{ - gboolean ret = FALSE; - GstTextOverlay *overlay = NULL; - - overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (pad, "received event %s", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT:{ - GstFormat fmt; - gboolean update; - gdouble rate, applied_rate; - gint64 cur, stop, time; - - overlay->text_eos = FALSE; - - gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, - &fmt, &cur, &stop, &time); - - if (fmt == GST_FORMAT_TIME) { - GST_OBJECT_LOCK (overlay); - gst_segment_set_newsegment_full (&overlay->text_segment, update, rate, - applied_rate, GST_FORMAT_TIME, cur, stop, time); - GST_DEBUG_OBJECT (overlay, "TEXT SEGMENT now: %" GST_SEGMENT_FORMAT, - &overlay->text_segment); - GST_OBJECT_UNLOCK (overlay); - } else { - GST_ELEMENT_WARNING (overlay, STREAM, MUX, (NULL), - ("received non-TIME newsegment event on text input")); - } - - gst_event_unref (event); - ret = TRUE; - - /* wake up the video chain, it might be waiting for a text buffer or - * a text segment update */ - GST_OBJECT_LOCK (overlay); - GST_TEXT_OVERLAY_BROADCAST (overlay); - GST_OBJECT_UNLOCK (overlay); - break; - } - case GST_EVENT_FLUSH_STOP: - GST_OBJECT_LOCK (overlay); - overlay->text_flushing = FALSE; - gst_text_overlay_pop_text (overlay); - GST_OBJECT_UNLOCK (overlay); - gst_event_unref (event); - ret = TRUE; - break; - case GST_EVENT_FLUSH_START: - GST_OBJECT_LOCK (overlay); - overlay->text_flushing = TRUE; - GST_TEXT_OVERLAY_BROADCAST (overlay); - GST_OBJECT_UNLOCK (overlay); - gst_event_unref (event); - ret = TRUE; - break; - case GST_EVENT_EOS: - GST_OBJECT_LOCK (overlay); - overlay->text_flushing = TRUE; - overlay->text_eos = TRUE; - GST_INFO_OBJECT (overlay, "EOS"); - /* wake up the video chain, it might be waiting for a text buffer or - * a text segment update */ - GST_TEXT_OVERLAY_BROADCAST (overlay); - GST_OBJECT_UNLOCK (overlay); - gst_event_unref (event); - ret = TRUE; - break; - default: - ret = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (overlay); - - return ret; -} - -static gboolean -gst_text_overlay_video_event (GstPad * pad, GstEvent * event) -{ - gboolean ret = FALSE; - GstTextOverlay *overlay = NULL; - - overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad)); - - GST_DEBUG_OBJECT (pad, "received event %s", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - { - GstFormat format; - gdouble rate; - gint64 start, stop, time; - gboolean update; - - GST_DEBUG_OBJECT (overlay, "received new segment"); - - gst_event_parse_new_segment (event, &update, &rate, &format, &start, - &stop, &time); - - if (format == GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (overlay, "VIDEO SEGMENT now: %" GST_SEGMENT_FORMAT, - overlay->segment); - - gst_segment_set_newsegment (overlay->segment, update, rate, format, - start, stop, time); - } else { - GST_ELEMENT_WARNING (overlay, STREAM, MUX, (NULL), - ("received non-TIME newsegment event on video input")); - } - - ret = gst_pad_event_default (pad, event); - break; - } - case GST_EVENT_EOS: - GST_OBJECT_LOCK (overlay); - overlay->video_flushing = TRUE; - overlay->text_flushing = TRUE; - gst_text_overlay_pop_text (overlay); - GST_OBJECT_UNLOCK (overlay); - ret = gst_pad_event_default (pad, event); - break; - case GST_EVENT_FLUSH_START: - GST_OBJECT_LOCK (overlay); - overlay->video_flushing = TRUE; - GST_TEXT_OVERLAY_BROADCAST (overlay); - GST_OBJECT_UNLOCK (overlay); - ret = gst_pad_event_default (pad, event); - break; - case GST_EVENT_FLUSH_STOP: - GST_OBJECT_LOCK (overlay); - overlay->video_flushing = FALSE; - GST_OBJECT_UNLOCK (overlay); - ret = gst_pad_event_default (pad, event); - break; - default: - ret = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (overlay); - - return ret; -} - -/* Called with lock held */ -static void -gst_text_overlay_pop_text (GstTextOverlay * overlay) -{ - g_return_if_fail (GST_IS_TEXT_OVERLAY (overlay)); - - if (overlay->text_buffer) { - /* update text_segment's last stop */ - if (overlay->text_segment.format == GST_FORMAT_TIME && - GST_BUFFER_TIMESTAMP_IS_VALID (overlay->text_buffer)) { - overlay->text_segment.last_stop = - GST_BUFFER_TIMESTAMP (overlay->text_buffer); - if (GST_BUFFER_DURATION_IS_VALID (overlay->text_buffer)) { - overlay->text_segment.last_stop += - GST_BUFFER_DURATION (overlay->text_buffer); - } - } - GST_DEBUG_OBJECT (overlay, "releasing text buffer %p", - overlay->text_buffer); - gst_buffer_unref (overlay->text_buffer); - overlay->text_buffer = NULL; - } - - /* Let the text task know we used that buffer */ - GST_TEXT_OVERLAY_BROADCAST (overlay); -} - -/* We receive text buffers here. If they are out of segment we just ignore them. - If the buffer is in our segment we keep it internally except if another one - is already waiting here, in that case we wait that it gets kicked out */ -static GstFlowReturn -gst_text_overlay_text_chain (GstPad * pad, GstBuffer * buffer) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstTextOverlay *overlay = NULL; - gboolean in_seg = FALSE; - gint64 clip_start = 0, clip_stop = 0; - - overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad)); - - GST_OBJECT_LOCK (overlay); - - if (overlay->text_eos) { - GST_OBJECT_UNLOCK (overlay); - ret = GST_FLOW_UNEXPECTED; - GST_LOG_OBJECT (overlay, "text EOS"); - goto beach; - } - - if (overlay->text_flushing) { - GST_OBJECT_UNLOCK (overlay); - ret = GST_FLOW_WRONG_STATE; - GST_LOG_OBJECT (overlay, "text flushing"); - goto beach; - } - - GST_LOG_OBJECT (overlay, "%" GST_SEGMENT_FORMAT " BUFFER: ts=%" - GST_TIME_FORMAT ", end=%" GST_TIME_FORMAT, overlay->segment, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer) + - GST_BUFFER_DURATION (buffer))); - - in_seg = gst_segment_clip (overlay->segment, GST_FORMAT_TIME, - GST_BUFFER_TIMESTAMP (buffer), - GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer), - &clip_start, &clip_stop); - - if (in_seg) { - GST_BUFFER_TIMESTAMP (buffer) = clip_start; - GST_BUFFER_DURATION (buffer) = clip_stop - clip_start; - - /* Wait for the previous buffer to go away */ - while (overlay->text_buffer != NULL) { - GST_DEBUG ("Pad %s:%s has a buffer queued, waiting", - GST_DEBUG_PAD_NAME (pad)); - GST_TEXT_OVERLAY_WAIT (overlay); - GST_DEBUG ("Pad %s:%s resuming", GST_DEBUG_PAD_NAME (pad)); - if (overlay->text_flushing) { - GST_OBJECT_UNLOCK (overlay); - ret = GST_FLOW_WRONG_STATE; - goto beach; - } - } - - overlay->text_buffer = buffer; - /* That's a new text buffer we need to render */ - overlay->need_render = TRUE; - - /* in case the video chain is waiting for a text buffer, wake it up */ - GST_TEXT_OVERLAY_BROADCAST (overlay); - } - - GST_OBJECT_UNLOCK (overlay); - -beach: - - return ret; -} - -static GstFlowReturn -gst_text_overlay_video_chain (GstPad * pad, GstBuffer * buffer) -{ - GstTextOverlayClass *klass; - GstTextOverlay *overlay; - GstFlowReturn ret = GST_FLOW_OK; - gboolean in_seg = FALSE; - gint64 start, stop, clip_start = 0, clip_stop = 0; - gchar *text = NULL; - - overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad)); - klass = GST_TEXT_OVERLAY_GET_CLASS (overlay); - - if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) - goto missing_timestamp; - - /* ignore buffers that are outside of the current segment */ - start = GST_BUFFER_TIMESTAMP (buffer); - - if (!GST_BUFFER_DURATION_IS_VALID (buffer)) { - stop = GST_CLOCK_TIME_NONE; - } else { - stop = start + GST_BUFFER_DURATION (buffer); - } - - GST_LOG_OBJECT (overlay, "%" GST_SEGMENT_FORMAT " BUFFER: ts=%" - GST_TIME_FORMAT ", end=%" GST_TIME_FORMAT, overlay->segment, - GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); - - /* segment_clip() will adjust start unconditionally to segment_start if - * no stop time is provided, so handle this ourselves */ - if (stop == GST_CLOCK_TIME_NONE && start < overlay->segment->start) - goto out_of_segment; - - in_seg = gst_segment_clip (overlay->segment, GST_FORMAT_TIME, start, stop, - &clip_start, &clip_stop); - - if (!in_seg) - goto out_of_segment; - - /* if the buffer is only partially in the segment, fix up stamps */ - if (clip_start != start || (stop != -1 && clip_stop != stop)) { - GST_DEBUG_OBJECT (overlay, "clipping buffer timestamp/duration to segment"); - buffer = gst_buffer_make_metadata_writable (buffer); - GST_BUFFER_TIMESTAMP (buffer) = clip_start; - if (stop != -1) - GST_BUFFER_DURATION (buffer) = clip_stop - clip_start; - } - - /* now, after we've done the clipping, fix up end time if there's no - * duration (we only use those estimated values internally though, we - * don't want to set bogus values on the buffer itself) */ - if (stop == -1) { - GstStructure *s; - gint fps_num, fps_denom; - - s = gst_caps_get_structure (GST_PAD_CAPS (pad), 0); - if (gst_structure_get_fraction (s, "framerate", &fps_num, &fps_denom)) { - GST_DEBUG_OBJECT (overlay, "estimating duration based on framerate"); - stop = start + gst_util_uint64_scale_int (GST_SECOND, fps_denom, fps_num); - } else { - GST_WARNING_OBJECT (overlay, "no duration, assuming minimal duration"); - stop = start + 1; /* we need to assume some interval */ - } - } - -wait_for_text_buf: - - GST_OBJECT_LOCK (overlay); - - if (overlay->video_flushing) - goto flushing; - - if (overlay->silent) { - GST_OBJECT_UNLOCK (overlay); - ret = gst_pad_push (overlay->srcpad, buffer); - - /* Update last_stop */ - gst_segment_set_last_stop (overlay->segment, GST_FORMAT_TIME, clip_start); - - return ret; - } - - /* Text pad not linked, rendering internal text */ - if (!overlay->text_linked) { - if (klass->get_text) { - text = klass->get_text (overlay, buffer); - } else { - text = g_strdup (overlay->default_text); - } - - GST_LOG_OBJECT (overlay, "Text pad not linked, rendering default " - "text: '%s'", GST_STR_NULL (text)); - - GST_OBJECT_UNLOCK (overlay); - - if (text != NULL && *text != '\0') { - /* Render and push */ - gst_text_overlay_render_text (overlay, text, -1); - ret = gst_text_overlay_push_frame (overlay, buffer); - } else { - /* Invalid or empty string */ - ret = gst_pad_push (overlay->srcpad, buffer); - } - } else { - /* Text pad linked, check if we have a text buffer queued */ - if (overlay->text_buffer) { - gboolean pop_text = FALSE; - gint64 text_start, text_end; - - /* if the text buffer isn't stamped right, pop it off the - * queue and display it for the current video frame only */ - if (!GST_BUFFER_TIMESTAMP_IS_VALID (overlay->text_buffer) || - !GST_BUFFER_DURATION_IS_VALID (overlay->text_buffer)) { - GST_WARNING_OBJECT (overlay, - "Got text buffer with invalid timestamp or duration"); - text_start = start; - text_end = stop; - pop_text = TRUE; - } else { - text_start = GST_BUFFER_TIMESTAMP (overlay->text_buffer); - text_end = text_start + GST_BUFFER_DURATION (overlay->text_buffer); - } - - GST_LOG_OBJECT (overlay, "T: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, - GST_TIME_ARGS (text_start), GST_TIME_ARGS (text_end)); - GST_LOG_OBJECT (overlay, "V: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, - GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); - - /* Text too old or in the future */ - if (text_end <= start) { - /* text buffer too old, get rid of it and do nothing */ - GST_LOG_OBJECT (overlay, "text buffer too old, popping"); - pop_text = FALSE; - gst_text_overlay_pop_text (overlay); - GST_OBJECT_UNLOCK (overlay); - goto wait_for_text_buf; - } else if (stop <= text_start) { - GST_LOG_OBJECT (overlay, "text in future, pushing video buf"); - GST_OBJECT_UNLOCK (overlay); - /* Push the video frame */ - ret = gst_pad_push (overlay->srcpad, buffer); - } else { - gchar *in_text; - gsize in_size; - - in_text = (gchar *) GST_BUFFER_DATA (overlay->text_buffer); - in_size = GST_BUFFER_SIZE (overlay->text_buffer); - - /* g_markup_escape_text() absolutely requires valid UTF8 input, it - * might crash otherwise. We don't fall back on GST_SUBTITLE_ENCODING - * here on purpose, this is something that needs fixing upstream */ - if (!g_utf8_validate (in_text, in_size, NULL)) { - const gchar *end = NULL; - - GST_WARNING_OBJECT (overlay, "received invalid UTF-8"); - in_text = g_strndup (in_text, in_size); - while (!g_utf8_validate (in_text, in_size, &end) && end) - *((gchar *) end) = '*'; - } - - /* Get the string */ - if (overlay->have_pango_markup) { - text = g_strndup (in_text, in_size); - } else { - text = g_markup_escape_text (in_text, in_size); - } - - if (text != NULL && *text != '\0') { - gint text_len = strlen (text); - - while (text_len > 0 && (text[text_len - 1] == '\n' || - text[text_len - 1] == '\r')) { - --text_len; - } - GST_DEBUG_OBJECT (overlay, "Rendering text '%*s'", text_len, text); - gst_text_overlay_render_text (overlay, text, text_len); - } else { - GST_DEBUG_OBJECT (overlay, "No text to render (empty buffer)"); - gst_text_overlay_render_text (overlay, " ", 1); - } - - if (in_text != (gchar *) GST_BUFFER_DATA (overlay->text_buffer)) - g_free (in_text); - - GST_OBJECT_UNLOCK (overlay); - ret = gst_text_overlay_push_frame (overlay, buffer); - - if (text_end <= stop) { - GST_LOG_OBJECT (overlay, "text buffer not needed any longer"); - pop_text = TRUE; - } - } - if (pop_text) { - GST_OBJECT_LOCK (overlay); - gst_text_overlay_pop_text (overlay); - GST_OBJECT_UNLOCK (overlay); - } - } else { - gboolean wait_for_text_buf = TRUE; - - if (overlay->text_eos) - wait_for_text_buf = FALSE; - - /* Text pad linked, but no text buffer available - what now? */ - if (overlay->text_segment.format == GST_FORMAT_TIME) { - if (GST_BUFFER_TIMESTAMP (buffer) < overlay->text_segment.start || - GST_BUFFER_TIMESTAMP (buffer) < overlay->text_segment.last_stop) { - wait_for_text_buf = FALSE; - } - } - - if (wait_for_text_buf) { - GST_DEBUG_OBJECT (overlay, "no text buffer, need to wait for one"); - GST_TEXT_OVERLAY_WAIT (overlay); - GST_DEBUG_OBJECT (overlay, "resuming"); - GST_OBJECT_UNLOCK (overlay); - goto wait_for_text_buf; - } else { - GST_OBJECT_UNLOCK (overlay); - GST_LOG_OBJECT (overlay, "no need to wait for a text buffer"); - ret = gst_pad_push (overlay->srcpad, buffer); - } - } - } - - g_free (text); - - /* Update last_stop */ - gst_segment_set_last_stop (overlay->segment, GST_FORMAT_TIME, clip_start); - - return ret; - -missing_timestamp: - { - GST_WARNING_OBJECT (overlay, "buffer without timestamp, discarding"); - gst_buffer_unref (buffer); - return GST_FLOW_OK; - } - -flushing: - { - GST_OBJECT_UNLOCK (overlay); - GST_DEBUG_OBJECT (overlay, "flushing, discarding buffer"); - gst_buffer_unref (buffer); - return GST_FLOW_WRONG_STATE; - } - -out_of_segment: - { - GST_DEBUG_OBJECT (overlay, "buffer out of segment, discarding"); - gst_buffer_unref (buffer); - return GST_FLOW_OK; - } -} - -static GstStateChangeReturn -gst_text_overlay_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstTextOverlay *overlay = GST_TEXT_OVERLAY (element); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_OBJECT_LOCK (overlay); - overlay->text_flushing = TRUE; - overlay->video_flushing = TRUE; - /* pop_text will broadcast on the GCond and thus also make the video - * chain exit if it's waiting for a text buffer */ - gst_text_overlay_pop_text (overlay); - GST_OBJECT_UNLOCK (overlay); - break; - default: - break; - } - - ret = parent_class->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - GST_OBJECT_LOCK (overlay); - overlay->text_flushing = FALSE; - overlay->video_flushing = FALSE; - GST_OBJECT_UNLOCK (overlay); - break; - default: - break; - } - - return ret; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "textoverlay", GST_RANK_NONE, - GST_TYPE_TEXT_OVERLAY) || - !gst_element_register (plugin, "timeoverlay", GST_RANK_NONE, - GST_TYPE_TIME_OVERLAY) || - !gst_element_register (plugin, "clockoverlay", GST_RANK_NONE, - GST_TYPE_CLOCK_OVERLAY) || - !gst_element_register (plugin, "textrender", GST_RANK_NONE, - GST_TYPE_TEXT_RENDER)) { - return FALSE; - } - - /*texttestsrc_plugin_init(module, plugin); */ - - GST_DEBUG_CATEGORY_INIT (pango_debug, "pango", 0, "Pango elements"); - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - "pango", "Pango-based text rendering and overlay", plugin_init, - VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/pango/gsttextoverlay.h --- a/gst_plugins_base/ext/pango/gsttextoverlay.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -#ifndef __GST_TEXT_OVERLAY_H__ -#define __GST_TEXT_OVERLAY_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_TEXT_OVERLAY (gst_text_overlay_get_type()) -#define GST_TEXT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ - GST_TYPE_TEXT_OVERLAY, GstTextOverlay)) -#define GST_TEXT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\ - GST_TYPE_TEXT_OVERLAY,GstTextOverlayClass)) -#define GST_TEXT_OVERLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ - GST_TYPE_TEXT_OVERLAY, GstTextOverlayClass)) -#define GST_IS_TEXT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\ - GST_TYPE_TEXT_OVERLAY)) -#define GST_IS_TEXT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\ - GST_TYPE_TEXT_OVERLAY)) - -typedef struct _GstTextOverlay GstTextOverlay; -typedef struct _GstTextOverlayClass GstTextOverlayClass; - -/** - * GstTextOverlayVAlign: - * @GST_TEXT_OVERLAY_VALIGN_BASELINE: draw text on the baseline - * @GST_TEXT_OVERLAY_VALIGN_BOTTOM: draw text on the bottom - * @GST_TEXT_OVERLAY_VALIGN_TOP: draw test on top - * - * Vertical alignment of the text. - */ -typedef enum { - GST_TEXT_OVERLAY_VALIGN_BASELINE, - GST_TEXT_OVERLAY_VALIGN_BOTTOM, - GST_TEXT_OVERLAY_VALIGN_TOP -} GstTextOverlayVAlign; - -/** - * GstTextOverlayHAlign: - * @GST_TEXT_OVERLAY_HALIGN_LEFT: align text left - * @GST_TEXT_OVERLAY_HALIGN_CENTER: align text center - * @GST_TEXT_OVERLAY_HALIGN_RIGHT: align text right - * - * Horizontal alignment of the text. - */ -typedef enum { - GST_TEXT_OVERLAY_HALIGN_LEFT, - GST_TEXT_OVERLAY_HALIGN_CENTER, - GST_TEXT_OVERLAY_HALIGN_RIGHT -} GstTextOverlayHAlign; - -/** - * GstTextOverlayWrapMode: - * @GST_TEXT_OVERLAY_WRAP_MODE_NONE: no wrapping - * @GST_TEXT_OVERLAY_WRAP_MODE_WORD: do word wrapping - * @GST_TEXT_OVERLAY_WRAP_MODE_CHAR: do char wrapping - * @GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR: do word and char wrapping - * - * Whether to wrap the text and if so how. - */ -typedef enum { - GST_TEXT_OVERLAY_WRAP_MODE_NONE = -1, - GST_TEXT_OVERLAY_WRAP_MODE_WORD = PANGO_WRAP_WORD, - GST_TEXT_OVERLAY_WRAP_MODE_CHAR = PANGO_WRAP_CHAR, - GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR = PANGO_WRAP_WORD_CHAR -} GstTextOverlayWrapMode; - -/** - * GstTextOverlayLineAlign: - * @GST_TEXT_OVERLAY_LINE_ALIGN_LEFT: lines are left-aligned - * @GST_TEXT_OVERLAY_LINE_ALIGN_CENTER: lines are center-aligned - * @GST_TEXT_OVERLAY_LINE_ALIGN_RIGHT: lines are right-aligned - * - * Alignment of text lines relative to each other - */ -typedef enum { - GST_TEXT_OVERLAY_LINE_ALIGN_LEFT = PANGO_ALIGN_LEFT, - GST_TEXT_OVERLAY_LINE_ALIGN_CENTER = PANGO_ALIGN_CENTER, - GST_TEXT_OVERLAY_LINE_ALIGN_RIGHT = PANGO_ALIGN_RIGHT -} GstTextOverlayLineAlign; - -/** - * GstTextOverlay: - * - * Opaque textoverlay object structure - */ -struct _GstTextOverlay { - GstElement element; - - GstPad *video_sinkpad; - GstPad *text_sinkpad; - GstPad *srcpad; - - GstSegment *segment; - GstSegment text_segment; - GstBuffer *text_buffer; - gboolean text_linked; - gboolean video_flushing; - gboolean text_flushing; - gboolean text_eos; - - GCond *cond; /* to signal removal of a queued text - * buffer, arrival of a text buffer, - * a text segment update, or a change - * in status (e.g. shutdown, flushing) */ - - gint width; - gint height; - gint fps_n; - gint fps_d; - - GstTextOverlayVAlign valign; - GstTextOverlayHAlign halign; - GstTextOverlayWrapMode wrap_mode; - GstTextOverlayLineAlign line_align; - - gint xpad; - gint ypad; - gint deltax; - gint deltay; - gchar *default_text; - gboolean want_shading; - gboolean silent; - - PangoLayout *layout; - FT_Bitmap bitmap; - gint bitmap_buffer_size; - gint baseline_y; - - gboolean need_render; - - gint shading_value; /* for timeoverlay subclass */ - - gboolean have_pango_markup; -}; - -struct _GstTextOverlayClass { - GstElementClass parent_class; - - PangoContext *pango_context; - - gchar * (*get_text) (GstTextOverlay *overlay, GstBuffer *video_frame); -}; - -GType gst_text_overlay_get_type(void) G_GNUC_CONST; - -G_END_DECLS - -#endif /* __GST_TEXT_OVERLAY_H */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/pango/gsttextrender.c --- a/gst_plugins_base/ext/pango/gsttextrender.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,382 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2003> David Schleef - * - * 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. - */ - - -/** - * SECTION:element-textrender - * @see_also: #GstTextOverlay - * - * - * - * This plugin renders text received on the text sink pad to a video - * buffer (retaining the alpha channel), so it can later be overlayed - * on top of video streams using other elements. - * - * - * The text can contain newline characters. (FIXME: What about text - * wrapping? It does not make sense in this context) - * - * - * Example pipeline: - * - * gst-launch -v filesrc location=subtitles.srt ! subparse ! textrender ! xvimagesink - * - * - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "gsttextrender.h" - -GST_DEBUG_CATEGORY_EXTERN (pango_debug); -#define GST_CAT_DEFAULT pango_debug - -static const GstElementDetails text_render_details = -GST_ELEMENT_DETAILS ("Text renderer", - "Filter/Editor/Video", - "Renders a text string to an image bitmap", - "David Schleef , " - "Ronald S. Bultje "); - -enum -{ - ARG_0, - ARG_FONT_DESC -}; - - -static GstStaticPadTemplate src_template_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")) - ); - -static GstStaticPadTemplate sink_template_factory = - GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("text/x-pango-markup; text/plain") - ); - -GST_BOILERPLATE (GstTextRender, gst_text_render, GstElement, GST_TYPE_ELEMENT) - - static void gst_text_render_finalize (GObject * object); - static void gst_text_render_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); - - static void gst_text_render_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_template_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_template_factory)); - - gst_element_class_set_details (element_class, &text_render_details); -} - -static void -gst_text_render_class_init (GstTextRenderClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = gst_text_render_finalize; - gobject_class->set_property = gst_text_render_set_property; - - klass->pango_context = pango_ft2_get_context (72, 72); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FONT_DESC, - g_param_spec_string ("font-desc", "font description", - "Pango font description of font " - "to be used for rendering. " - "See documentation of " - "pango_font_description_from_string" - " for syntax.", "", G_PARAM_WRITABLE)); -} - - -static void -resize_bitmap (GstTextRender * render, gint width, gint height) -{ - FT_Bitmap *bitmap = &render->bitmap; - gint pitch = (width | 3) + 1; - gint size = pitch * height; - - /* no need to keep reallocating; just keep the maximum size so far */ - if (size <= render->bitmap_buffer_size) { - bitmap->rows = height; - bitmap->width = width; - bitmap->pitch = pitch; - memset (bitmap->buffer, 0, render->bitmap_buffer_size); - return; - } - if (!bitmap->buffer) { - /* initialize */ - bitmap->pixel_mode = ft_pixel_mode_grays; - bitmap->num_grays = 256; - } - if (bitmap->buffer) - bitmap->buffer = g_realloc (bitmap->buffer, size); - else - bitmap->buffer = g_malloc (size); - bitmap->rows = height; - bitmap->width = width; - bitmap->pitch = pitch; - memset (bitmap->buffer, 0, size); - render->bitmap_buffer_size = size; -} - -static void -gst_text_render_render_text (GstTextRender * render) -{ - PangoRectangle ink_rect, logical_rect; - - pango_layout_get_pixel_extents (render->layout, &ink_rect, &logical_rect); - resize_bitmap (render, ink_rect.width, ink_rect.height + ink_rect.y); - pango_ft2_render_layout (&render->bitmap, render->layout, -ink_rect.x, 0); - render->baseline_y = ink_rect.y; -} - -static gboolean -gst_text_render_setcaps (GstPad * pad, GstCaps * caps) -{ - GstTextRender *render = GST_TEXT_RENDER (gst_pad_get_parent (pad)); - GstStructure *structure; - gboolean ret = FALSE; - gint width = 0, height = 0; - - structure = gst_caps_get_structure (caps, 0); - gst_structure_get_int (structure, "width", &width); - gst_structure_get_int (structure, "height", &height); - - GST_DEBUG ("Got caps %" GST_PTR_FORMAT, caps); - - if (width >= render->bitmap.width && height >= render->bitmap.rows) { - render->width = width; - render->height = height; - ret = TRUE; - } - - gst_object_unref (render); - return ret; -} - -static void -gst_text_render_fixate_caps (GstPad * pad, GstCaps * caps) -{ - GstTextRender *render = GST_TEXT_RENDER (gst_pad_get_parent (pad)); - GstStructure *s = gst_caps_get_structure (caps, 0); - - GST_DEBUG ("Fixating caps %" GST_PTR_FORMAT, caps); - gst_structure_fixate_field_nearest_int (s, "width", render->bitmap.width); - gst_structure_fixate_field_nearest_int (s, "height", render->bitmap.rows); - GST_DEBUG ("Fixated to %" GST_PTR_FORMAT, caps); - - gst_object_unref (render); -} - -static void -gst_text_renderer_bitmap_to_ayuv (GstTextRender * render, FT_Bitmap * bitmap, - guchar * pixbuf) -{ - int y; /* text bitmap coordinates */ - int rowinc, bit_rowinc; - guchar *p, *bitp; - guchar v; - - rowinc = render->width - bitmap->width; - bit_rowinc = bitmap->pitch - bitmap->width; - - bitp = bitmap->buffer; - p = pixbuf; - - for (y = 0; y < bitmap->rows; y++) { - int n; - - for (n = bitmap->width; n > 0; --n) { - v = *bitp; - if (v) { - p[0] = v; - p[1] = 255; - p[2] = 0x80; - p[3] = 0x80; - } - p += 4; - bitp++; - } - p += rowinc * 4; - bitp += bit_rowinc; - } -} - - -static GstFlowReturn -gst_text_render_chain (GstPad * pad, GstBuffer * inbuf) -{ - GstTextRender *render; - GstFlowReturn ret; - GstBuffer *outbuf; - GstCaps *caps = NULL; - guint8 *data = GST_BUFFER_DATA (inbuf); - guint size = GST_BUFFER_SIZE (inbuf); - gint n; - - render = GST_TEXT_RENDER (gst_pad_get_parent (pad)); - - /* somehow pango barfs over "\0" buffers... */ - while (size > 0 && - (data[size - 1] == '\r' || - data[size - 1] == '\n' || data[size - 1] == '\0')) { - size--; - } - - /* render text */ - GST_DEBUG ("rendering '%*s'", size, data); - pango_layout_set_markup (render->layout, (gchar *) data, size); - gst_text_render_render_text (render); - - caps = gst_caps_new_simple ("video/x-raw-yuv", "format", GST_TYPE_FOURCC, - GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'), "width", G_TYPE_INT, - render->bitmap.width, "height", G_TYPE_INT, render->bitmap.rows, - "framerate", GST_TYPE_FRACTION, 1, 1, NULL); - - if (!gst_pad_set_caps (render->srcpad, caps)) { - gst_caps_unref (caps); - GST_ELEMENT_ERROR (render, CORE, NEGOTIATION, (NULL), (NULL)); - ret = GST_FLOW_ERROR; - goto done; - } - - GST_DEBUG ("Allocating AYUV buffer WxH = %dx%d", render->width, - render->height); - ret = - gst_pad_alloc_buffer_and_set_caps (render->srcpad, GST_BUFFER_OFFSET_NONE, - render->width * render->height * 4, caps, &outbuf); - - if (ret != GST_FLOW_OK) - goto done; - - gst_buffer_copy_metadata (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS); - data = GST_BUFFER_DATA (outbuf); - - for (n = 0; n < render->width * render->height; n++) { - data[n * 4] = 0; - data[n * 4 + 1] = 0; - data[n * 4 + 2] = data[n * 4 + 3] = 128; - } - - if (render->bitmap.buffer) { - gst_text_renderer_bitmap_to_ayuv (render, &render->bitmap, data); - } - - ret = gst_pad_push (render->srcpad, outbuf); - -done: - if (caps) - gst_caps_unref (caps); - gst_buffer_unref (inbuf); - gst_object_unref (render); - return ret; -} - -static void -gst_text_render_finalize (GObject * object) -{ - GstTextRender *render = GST_TEXT_RENDER (object); - - g_free (render->bitmap.buffer); - - if (render->layout) - g_object_unref (render->layout); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_text_render_init (GstTextRender * render, GstTextRenderClass * klass) -{ - GstPadTemplate *template; - - /* sink */ - template = gst_static_pad_template_get (&sink_template_factory); - render->sinkpad = gst_pad_new_from_template (template, "sink"); - gst_object_unref (template); - gst_pad_set_chain_function (render->sinkpad, - GST_DEBUG_FUNCPTR (gst_text_render_chain)); - gst_element_add_pad (GST_ELEMENT (render), render->sinkpad); - - /* source */ - template = gst_static_pad_template_get (&src_template_factory); - render->srcpad = gst_pad_new_from_template (template, "src"); - gst_object_unref (template); - gst_pad_set_fixatecaps_function (render->srcpad, - GST_DEBUG_FUNCPTR (gst_text_render_fixate_caps)); - gst_pad_set_setcaps_function (render->srcpad, - GST_DEBUG_FUNCPTR (gst_text_render_setcaps)); - gst_element_add_pad (GST_ELEMENT (render), render->srcpad); - - render->layout = - pango_layout_new (GST_TEXT_RENDER_GET_CLASS (render)->pango_context); - memset (&render->bitmap, 0, sizeof (render->bitmap)); -} - -static void -gst_text_render_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstTextRender *render = GST_TEXT_RENDER (object); - - switch (prop_id) { - case ARG_FONT_DESC: - { - PangoFontDescription *desc; - - desc = pango_font_description_from_string (g_value_get_string (value)); - if (desc) { - GST_LOG ("font description set: %s", g_value_get_string (value)); - GST_OBJECT_LOCK (render); - pango_layout_set_font_description (render->layout, desc); - pango_font_description_free (desc); - gst_text_render_render_text (render); - GST_OBJECT_UNLOCK (render); - } else { - GST_WARNING ("font description parse failed: %s", - g_value_get_string (value)); - } - break; - } - - default: - break; - } -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/pango/gsttextrender.h --- a/gst_plugins_base/ext/pango/gsttextrender.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -#ifndef __GST_TEXT_RENDER_H__ -#define __GST_TEXT_RENDER_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_TEXT_RENDER (gst_text_render_get_type()) -#define GST_TEXT_RENDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ - GST_TYPE_TEXT_RENDER, GstTextRender)) -#define GST_TEXT_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\ - GST_TYPE_TEXT_RENDER, GstTextRenderClass)) -#define GST_TEXT_RENDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ - GST_TYPE_TEXT_RENDER, GstTextRenderClass)) -#define GST_IS_TEXT_RENDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\ - GST_TYPE_TEXT_RENDER)) -#define GST_IS_TEXT_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\ - GST_TYPE_TEXT_RENDER)) - -typedef struct _GstTextRender GstTextRender; -typedef struct _GstTextRenderClass GstTextRenderClass; - -/** - * GstTextRender: - * - * Opaque textrender data structure. - */ -struct _GstTextRender { - GstElement element; - - GstPad *sinkpad, *srcpad; - gint width; - gint height; - PangoLayout *layout; - FT_Bitmap bitmap; - gint bitmap_buffer_size; - gint baseline_y; -}; - -struct _GstTextRenderClass { - GstElementClass parent_class; - - PangoContext *pango_context; -}; - -GType gst_text_render_get_type(void) G_GNUC_CONST; - -G_END_DECLS - -#endif /* __GST_TEXT_RENDER_H */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/pango/gsttimeoverlay.c --- a/gst_plugins_base/ext/pango/gsttimeoverlay.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2005> Tim-Philipp Müller - * - * 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. - */ - -/** - * SECTION:element-timeoverlay - * @see_also: #GstTextOverlay, #GstClockOverlay - * - * - * - * This element overlays the buffer time stamps of a video stream on - * top of itself. You can position the text and configure the font details - * using the properties of the #GstTextOverlay class. By default, the - * time stamp is displayed in the top left corner of the picture, with some - * padding to the left and to the top. - * - * - * Here is a simple pipeline that displays the time stamps in the top left - * corner of the video picture: - * - * gst-launch -v videotestsrc ! timeoverlay ! xvimagesink - * - * - * - * Here is another pipeline that displays the time stamps with some leading - * text in the bottom right corner of the video picture, with the background - * of the text being shaded in order to make it more legible on top of a - * bright video background: - * - * gst-launch -v videotestsrc ! timeoverlay halign=right valign=bottom text="Stream time:" shaded-background=true ! xvimagesink - * - * - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include - -static const GstElementDetails time_overlay_details = -GST_ELEMENT_DETAILS ("Time overlay", - "Filter/Editor/Video", - "Overlays buffer time stamps on a video stream", - "Tim-Philipp Müller "); - -GST_BOILERPLATE (GstTimeOverlay, gst_time_overlay, GstTextOverlay, - GST_TYPE_TEXT_OVERLAY) - - static void gst_time_overlay_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &time_overlay_details); -} - -static gchar * -gst_time_overlay_render_time (GstTimeOverlay * overlay, GstClockTime time) -{ - guint hours, mins, secs, msecs; - - if (!GST_CLOCK_TIME_IS_VALID (time)) - return g_strdup (""); - - hours = (guint) (time / (GST_SECOND * 60 * 60)); - mins = (guint) ((time / (GST_SECOND * 60)) % 60); - secs = (guint) ((time / GST_SECOND) % 60); - msecs = (guint) ((time % GST_SECOND) / (1000 * 1000)); - - return g_strdup_printf ("%u:%02u:%02u.%03u", hours, mins, secs, msecs); -} - -/* Called with lock held */ -static gchar * -gst_time_overlay_get_text (GstTextOverlay * overlay, GstBuffer * video_frame) -{ - GstClockTime time = GST_BUFFER_TIMESTAMP (video_frame); - gchar *time_str, *txt, *ret; - - overlay->need_render = TRUE; - - if (!GST_CLOCK_TIME_IS_VALID (time)) { - GST_DEBUG ("buffer without valid timestamp"); - return g_strdup (""); - } - - GST_DEBUG ("buffer with timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (time)); - - txt = g_strdup (overlay->default_text); - - time_str = gst_time_overlay_render_time (GST_TIME_OVERLAY (overlay), time); - if (txt != NULL && *txt != '\0') { - ret = g_strdup_printf ("%s %s", txt, time_str); - } else { - ret = time_str; - time_str = NULL; - } - - g_free (txt); - g_free (time_str); - - return ret; -} - -static void -gst_time_overlay_class_init (GstTimeOverlayClass * klass) -{ - GstTextOverlayClass *gsttextoverlay_class; - - gsttextoverlay_class = (GstTextOverlayClass *) klass; - - gsttextoverlay_class->get_text = gst_time_overlay_get_text; -} - -static void -gst_time_overlay_init (GstTimeOverlay * overlay, GstTimeOverlayClass * klass) -{ - PangoFontDescription *font_description; - GstTextOverlay *textoverlay; - PangoContext *context; - - textoverlay = GST_TEXT_OVERLAY (overlay); - - context = GST_TEXT_OVERLAY_CLASS (klass)->pango_context; - - pango_context_set_language (context, pango_language_from_string ("en_US")); - pango_context_set_base_dir (context, PANGO_DIRECTION_LTR); - - font_description = pango_font_description_new (); - pango_font_description_set_family_static (font_description, "Monospace"); - pango_font_description_set_style (font_description, PANGO_STYLE_NORMAL); - pango_font_description_set_variant (font_description, PANGO_VARIANT_NORMAL); - pango_font_description_set_weight (font_description, PANGO_WEIGHT_NORMAL); - pango_font_description_set_stretch (font_description, PANGO_STRETCH_NORMAL); - pango_font_description_set_size (font_description, 18 * PANGO_SCALE); - pango_context_set_font_description (context, font_description); - pango_font_description_free (font_description); - - textoverlay->valign = GST_TEXT_OVERLAY_VALIGN_TOP; - textoverlay->halign = GST_TEXT_OVERLAY_HALIGN_LEFT; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/pango/gsttimeoverlay.h --- a/gst_plugins_base/ext/pango/gsttimeoverlay.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2005> Tim-Philipp Müller - * - * 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. - */ - - -#ifndef __GST_TIME_OVERLAY_H__ -#define __GST_TIME_OVERLAY_H__ - -#include "gsttextoverlay.h" - -G_BEGIN_DECLS - -#define GST_TYPE_TIME_OVERLAY \ - (gst_time_overlay_get_type()) -#define GST_TIME_OVERLAY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TIME_OVERLAY,GstTimeOverlay)) -#define GST_TIME_OVERLAY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TIME_OVERLAY,GstTimeOverlayClass)) -#define GST_IS_TIME_OVERLAY(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TIME_OVERLAY)) -#define GST_IS_TIME_OVERLAY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TIME_OVERLAY)) - -typedef struct _GstTimeOverlay GstTimeOverlay; -typedef struct _GstTimeOverlayClass GstTimeOverlayClass; - -/** - * GstTimeOverlay: - * - * Opaque timeoverlay data structure. - */ -struct _GstTimeOverlay { - GstTextOverlay textoverlay; -}; - -struct _GstTimeOverlayClass { - GstTextOverlayClass parent_class; -}; - -GType gst_time_overlay_get_type (void); - -G_END_DECLS - -#endif /* __GST_TIME_OVERLAY_H__ */ - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/theora/gsttheoradec.h --- a/gst_plugins_base/ext/theora/gsttheoradec.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Benjamin Otte - * - * 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. - */ - -#ifndef __GST_THEORADEC_H__ -#define __GST_THEORADEC_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_THEORA_DEC \ - (gst_theora_dec_get_type()) -#define GST_THEORA_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THEORA_DEC,GstTheoraDec)) -#define GST_THEORA_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THEORA_DEC,GstTheoraDecClass)) -#define GST_IS_THEORA_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THEORA_DEC)) -#define GST_IS_THEORA_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THEORA_DEC)) - -typedef struct _GstTheoraDec GstTheoraDec; -typedef struct _GstTheoraDecClass GstTheoraDecClass; - -/** - * GstTheoraDec: - * - * Opaque object data structure. - */ -struct _GstTheoraDec -{ - GstElement element; - - /* Pads */ - GstPad *sinkpad; - GstPad *srcpad; - - /* theora decoder state */ - theora_state state; - theora_info info; - theora_comment comment; - - gboolean have_header; - gboolean sent_newsegment; - gboolean is_old_bitstream; - guint64 granulepos; - guint64 granule_shift; - - GstClockTime last_timestamp; - guint64 frame_nr; /* unused */ - gboolean need_keyframe; - gint width, height; - gint offset_x, offset_y; - - gboolean crop; - - /* list of buffers that need timestamps */ - GList *queued; - /* list of raw output buffers */ - GList *output; - /* gather/decode queues for reverse playback */ - GList *gather; - GList *decode; - - GstTagList *tags; - - /* segment info */ /* with STREAM_LOCK */ - GstSegment segment; - gboolean discont; - - /* QoS stuff */ /* with LOCK*/ - gdouble proportion; - GstClockTime earliest_time; -}; - -struct _GstTheoraDecClass -{ - GstElementClass parent_class; -}; - -G_END_DECLS - -#endif /* __GST_THEORADEC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/theora/gsttheoraenc.h --- a/gst_plugins_base/ext/theora/gsttheoraenc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Wim Taymans - * - * 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. - */ - -#ifndef __GST_THEORAENC_H__ -#define __GST_THEORAENC_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_THEORA_ENC \ - (gst_theora_enc_get_type()) -#define GST_THEORA_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THEORA_ENC,GstTheoraEnc)) -#define GST_THEORA_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THEORA_ENC,GstTheoraEncClass)) -#define GST_IS_THEORA_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THEORA_ENC)) -#define GST_IS_THEORA_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THEORA_ENC)) - -typedef struct _GstTheoraEnc GstTheoraEnc; -typedef struct _GstTheoraEncClass GstTheoraEncClass; - -/** - * GstTheoraEncBorderMode: - * @BORDER_NONE: no border - * @BORDER_BLACK: black border - * @BORDER_MIRROR: Mirror image in border - * - * Border color to add when sizes not multiple of 16. - */ -typedef enum -{ - BORDER_NONE, - BORDER_BLACK, - BORDER_MIRROR -} -GstTheoraEncBorderMode; - -/** - * GstTheoraEnc: - * - * Opaque data structure. - */ -struct _GstTheoraEnc -{ - GstElement element; - - GstPad *sinkpad; - GstPad *srcpad; - - ogg_stream_state to; - - theora_state state; - theora_info info; - theora_comment comment; - gboolean initialised; - - gboolean center; - GstTheoraEncBorderMode border; - - gint video_bitrate; /* bitrate target for Theora video */ - gint video_quality; /* Theora quality selector 0 = low, 63 = high */ - gboolean quick; - gboolean keyframe_auto; - gint keyframe_freq; - gint keyframe_force; - gint keyframe_threshold; - gint keyframe_mindistance; - gint noise_sensitivity; - gint sharpness; - - gint info_width, info_height; - gint width, height; - gint offset_x, offset_y; - gint fps_n, fps_d; - GstClockTime next_ts; - - GstClockTime expected_ts; - gboolean next_discont; - - guint packetno; - guint64 bytes_out; - guint64 granulepos_offset; - guint64 timestamp_offset; - gint granule_shift; -}; - -struct _GstTheoraEncClass -{ - GstElementClass parent_class; -}; - -G_END_DECLS - -#endif /* __GST_THEORAENC_H__ */ - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/theora/gsttheoraparse.h --- a/gst_plugins_base/ext/theora/gsttheoraparse.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* -*- c-basic-offset: 2 -*- - * GStreamer - * Copyright (C) <2004> Thomas Vander Stichele - * Copyright (C) 2006 Andy Wingo - * - * 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. - */ - - -#ifndef __GST_THEORA_PARSE_H__ -#define __GST_THEORA_PARSE_H__ - - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_THEORA_PARSE \ - (gst_theora_parse_get_type()) -#define GST_THEORA_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THEORA_PARSE,GstTheoraParse)) -#define GST_THEORA_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THEORA_PARSE,GstTheoraParseClass)) -#define GST_IS_THEORA_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THEORA_PARSE)) -#define GST_IS_THEORA_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THEORA_PARSE)) - -typedef struct _GstTheoraParse GstTheoraParse; -typedef struct _GstTheoraParseClass GstTheoraParseClass; - -/** - * GstTheoraParse: - * - * Opaque data structure. - */ -struct _GstTheoraParse { - GstElement element; - - GstPad * sinkpad; - GstPad * srcpad; - - guint packetno; - gboolean send_streamheader; - gboolean streamheader_received; - gboolean is_old_bitstream; - GstBuffer * streamheader[3]; - - GQueue * event_queue; - GQueue * buffer_queue; - - theora_info info; - theora_comment comment; - - gint64 prev_frame; - gint64 prev_keyframe; - guint32 fps_n; - guint32 fps_d; - gint shift; - gint64 granule_offset; - - GstClockTime *times; - gint npairs; -}; - -struct _GstTheoraParseClass { - GstElementClass parent_class; -}; - -GType gst_theora_parse_get_type(void); - -G_END_DECLS - -#endif /* __GST_THEORA_PARSE_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/theora/theora.c --- a/gst_plugins_base/ext/theora/theora.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Benjamin Otte - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -extern GType gst_theora_dec_get_type (void); -extern GType gst_theora_enc_get_type (void); -extern GType gst_theora_parse_get_type (void); - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "theoradec", GST_RANK_PRIMARY, - gst_theora_dec_get_type ())) - return FALSE; - - if (!gst_element_register (plugin, "theoraenc", GST_RANK_NONE, - gst_theora_enc_get_type ())) - return FALSE; - - if (!gst_element_register (plugin, "theoraparse", GST_RANK_NONE, - gst_theora_parse_get_type ())) - return FALSE; - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "theora", - "Theora plugin library", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/theora/theoradec.c --- a/gst_plugins_base/ext/theora/theoradec.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1547 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Benjamin Otte - * - * 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. - */ - -/** - * SECTION:element-theoradec - * @see_also: theoraenc, oggdemux - * - * - * - * This element decodes theora streams into raw video - * Theora is a royalty-free - * video codec maintained by the Xiph.org - * Foundation, based on the VP3 codec. - * - * - * - * Example pipeline - * - * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! xvimagesink - * - * This example pipeline will decode an ogg stream and decodes the theora video. Refer to - * the theoraenc example to create the ogg file. - * - * - * Last reviewed on 2006-03-01 (0.10.4) - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "gsttheoradec.h" -#include - -#define GST_CAT_DEFAULT theoradec_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -#define THEORA_DEF_CROP TRUE -enum -{ - ARG_0, - ARG_CROP -}; - -static const GstElementDetails theora_dec_details = -GST_ELEMENT_DETAILS ("Theora video decoder", - "Codec/Decoder/Video", - "decode raw theora streams to raw YUV video", - "Benjamin Otte , " - "Wim Taymans "); - -static GstStaticPadTemplate theora_dec_src_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw-yuv, " - "format = (fourcc) I420, " - "framerate = (fraction) [0/1, MAX], " - "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]") - ); - -static GstStaticPadTemplate theora_dec_sink_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-theora") - ); - -GST_BOILERPLATE (GstTheoraDec, gst_theora_dec, GstElement, GST_TYPE_ELEMENT); - -static void theora_dec_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void theora_dec_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); - -static gboolean theora_dec_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn theora_dec_chain (GstPad * pad, GstBuffer * buffer); -static GstStateChangeReturn theora_dec_change_state (GstElement * element, - GstStateChange transition); -static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event); -static gboolean theora_dec_src_query (GstPad * pad, GstQuery * query); -static gboolean theora_dec_src_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value); -static gboolean theora_dec_sink_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value); -static gboolean theora_dec_sink_query (GstPad * pad, GstQuery * query); - -#if 0 -static const GstFormat *theora_get_formats (GstPad * pad); -#endif -#if 0 -static const GstEventMask *theora_get_event_masks (GstPad * pad); -#endif -static const GstQueryType *theora_get_query_types (GstPad * pad); - - -static void -gst_theora_dec_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&theora_dec_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&theora_dec_sink_factory)); - gst_element_class_set_details (element_class, &theora_dec_details); -} - -static void -gst_theora_dec_class_init (GstTheoraDecClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - - gobject_class->set_property = theora_dec_set_property; - gobject_class->get_property = theora_dec_get_property; - - g_object_class_install_property (gobject_class, ARG_CROP, - g_param_spec_boolean ("crop", "Crop", - "Crop the image to the visible region", THEORA_DEF_CROP, - (GParamFlags) G_PARAM_READWRITE)); - - gstelement_class->change_state = theora_dec_change_state; - - GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder"); -} - -static void -gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class) -{ - dec->sinkpad = - gst_pad_new_from_static_template (&theora_dec_sink_factory, "sink"); - gst_pad_set_query_function (dec->sinkpad, theora_dec_sink_query); - gst_pad_set_event_function (dec->sinkpad, theora_dec_sink_event); - gst_pad_set_chain_function (dec->sinkpad, theora_dec_chain); - gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad); - - dec->srcpad = - gst_pad_new_from_static_template (&theora_dec_src_factory, "src"); - gst_pad_set_event_function (dec->srcpad, theora_dec_src_event); - gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types); - gst_pad_set_query_function (dec->srcpad, theora_dec_src_query); - gst_pad_use_fixed_caps (dec->srcpad); - - gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad); - - dec->crop = THEORA_DEF_CROP; - dec->gather = NULL; - dec->decode = NULL; - dec->queued = NULL; -} - -static void -gst_theora_dec_reset (GstTheoraDec * dec) -{ - dec->need_keyframe = TRUE; - dec->sent_newsegment = FALSE; - dec->last_timestamp = -1; - dec->granulepos = -1; - dec->discont = TRUE; - dec->frame_nr = -1; - gst_segment_init (&dec->segment, GST_FORMAT_TIME); - - GST_OBJECT_LOCK (dec); - dec->proportion = 1.0; - dec->earliest_time = -1; - GST_OBJECT_UNLOCK (dec); - - g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->queued); - dec->queued = NULL; - g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->gather); - dec->gather = NULL; - g_list_foreach (dec->decode, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->decode); - dec->decode = NULL; - - if (dec->tags) { - gst_tag_list_free (dec->tags); - dec->tags = NULL; - } -} - -static int -_theora_ilog (unsigned int v) -{ - int ret = 0; - - while (v) { - ret++; - v >>= 1; - } - return (ret); -} - -/* Return the frame number (starting from zero) corresponding to this - * granulepos */ -static gint64 -_theora_granule_frame (GstTheoraDec * dec, gint64 granulepos) -{ - guint ilog; - gint framenum; - - if (granulepos == -1) - return -1; - - ilog = dec->granule_shift; - - /* granulepos is last ilog bits for counting pframes since last iframe and - * bits in front of that for the framenumber of the last iframe. */ - framenum = granulepos >> ilog; - framenum += granulepos - (framenum << ilog); - - /* This is 0-based for old bitstreams, 1-based for new. Fix up. */ - if (!dec->is_old_bitstream) - framenum -= 1; - - GST_DEBUG_OBJECT (dec, "framecount=%d, ilog=%u", framenum, ilog); - - return framenum; -} - -/* Return the frame start time corresponding to this granulepos */ -static GstClockTime -_theora_granule_start_time (GstTheoraDec * dec, gint64 granulepos) -{ - gint64 framecount; - - /* invalid granule results in invalid time */ - if (granulepos == -1) - return -1; - - /* get framecount */ - framecount = _theora_granule_frame (dec, granulepos); - - return gst_util_uint64_scale_int (framecount * GST_SECOND, - dec->info.fps_denominator, dec->info.fps_numerator); -} - -static gint64 -_inc_granulepos (GstTheoraDec * dec, gint64 granulepos) -{ - gint framecount; - - if (granulepos == -1) - return -1; - - framecount = _theora_granule_frame (dec, granulepos); - - return (framecount + 1 + - (dec->is_old_bitstream ? 0 : 1)) << dec->granule_shift; -} - -#if 0 -static const GstFormat * -theora_get_formats (GstPad * pad) -{ - static GstFormat src_formats[] = { - GST_FORMAT_DEFAULT, /* frames in this case */ - GST_FORMAT_TIME, - GST_FORMAT_BYTES, - 0 - }; - static GstFormat sink_formats[] = { - GST_FORMAT_DEFAULT, - GST_FORMAT_TIME, - 0 - }; - - return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats); -} -#endif - -#if 0 -static const GstEventMask * -theora_get_event_masks (GstPad * pad) -{ - static const GstEventMask theora_src_event_masks[] = { - {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH}, - {0,} - }; - - return theora_src_event_masks; -} -#endif - -static const GstQueryType * -theora_get_query_types (GstPad * pad) -{ - static const GstQueryType theora_src_query_types[] = { - GST_QUERY_POSITION, - GST_QUERY_DURATION, - GST_QUERY_CONVERT, - 0 - }; - - return theora_src_query_types; -} - - -static gboolean -theora_dec_src_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = TRUE; - GstTheoraDec *dec; - guint64 scale = 1; - - if (src_format == *dest_format) { - *dest_value = src_value; - return TRUE; - } - - dec = GST_THEORA_DEC (gst_pad_get_parent (pad)); - - /* we need the info part before we can done something */ - if (!dec->have_header) - goto no_header; - - switch (src_format) { - case GST_FORMAT_BYTES: - switch (*dest_format) { - case GST_FORMAT_DEFAULT: - *dest_value = gst_util_uint64_scale_int (src_value, 2, - dec->info.height * dec->info.width * 3); - break; - case GST_FORMAT_TIME: - /* seems like a rather silly conversion, implement me if you like */ - default: - res = FALSE; - } - break; - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_BYTES: - scale = 3 * (dec->info.width * dec->info.height) / 2; - case GST_FORMAT_DEFAULT: - *dest_value = scale * gst_util_uint64_scale (src_value, - dec->info.fps_numerator, dec->info.fps_denominator * GST_SECOND); - break; - default: - res = FALSE; - } - break; - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_TIME: - *dest_value = gst_util_uint64_scale (src_value, - GST_SECOND * dec->info.fps_denominator, dec->info.fps_numerator); - break; - case GST_FORMAT_BYTES: - *dest_value = gst_util_uint64_scale_int (src_value, - 3 * dec->info.width * dec->info.height, 2); - break; - default: - res = FALSE; - } - break; - default: - res = FALSE; - } -done: - gst_object_unref (dec); - return res; - - /* ERRORS */ -no_header: - { - GST_DEBUG_OBJECT (dec, "no header yet, cannot convert"); - res = FALSE; - goto done; - } -} - -static gboolean -theora_dec_sink_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = TRUE; - GstTheoraDec *dec; - - if (src_format == *dest_format) { - *dest_value = src_value; - return TRUE; - } - - dec = GST_THEORA_DEC (gst_pad_get_parent (pad)); - - /* we need the info part before we can done something */ - if (!dec->have_header) - goto no_header; - - switch (src_format) { - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_TIME: - *dest_value = _theora_granule_start_time (dec, src_value); - break; - default: - res = FALSE; - } - break; - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_DEFAULT: - { - guint rest; - - /* framecount */ - *dest_value = gst_util_uint64_scale (src_value, - dec->info.fps_numerator, GST_SECOND * dec->info.fps_denominator); - - /* funny way of calculating granulepos in theora */ - rest = *dest_value / dec->info.keyframe_frequency_force; - *dest_value -= rest; - *dest_value <<= dec->granule_shift; - *dest_value += rest; - break; - } - default: - res = FALSE; - break; - } - break; - default: - res = FALSE; - } -done: - gst_object_unref (dec); - return res; - - /* ERRORS */ -no_header: - { - GST_DEBUG_OBJECT (dec, "no header yet, cannot convert"); - res = FALSE; - goto done; - } -} - -static gboolean -theora_dec_src_query (GstPad * pad, GstQuery * query) -{ - GstTheoraDec *dec; - - gboolean res = FALSE; - - dec = GST_THEORA_DEC (gst_pad_get_parent (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - { - gint64 granulepos, value; - GstFormat my_format, format; - gint64 time; - - /* we can convert a granule position to everything */ - granulepos = dec->granulepos; - - GST_LOG_OBJECT (dec, - "query %p: we have current granule: %lld", query, granulepos); - - /* parse format */ - gst_query_parse_position (query, &format, NULL); - - /* and convert to the final format in two steps with time as the - * intermediate step */ - my_format = GST_FORMAT_TIME; - if (!(res = - theora_dec_sink_convert (dec->sinkpad, GST_FORMAT_DEFAULT, - granulepos, &my_format, &time))) - goto error; - - time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time); - - GST_LOG_OBJECT (dec, - "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time)); - - if (!(res = - theora_dec_src_convert (pad, my_format, time, &format, &value))) - goto error; - - gst_query_set_position (query, format, value); - - GST_LOG_OBJECT (dec, - "query %p: we return %lld (format %u)", query, value, format); - - break; - } - case GST_QUERY_DURATION: - { - GstPad *peer; - - if (!(peer = gst_pad_get_peer (dec->sinkpad))) - goto error; - - /* forward to peer for total */ - res = gst_pad_query (peer, query); - gst_object_unref (peer); - if (!res) - goto error; - - break; - } - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - if (!(res = - theora_dec_src_convert (pad, src_fmt, src_val, &dest_fmt, - &dest_val))) - goto error; - - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } -done: - gst_object_unref (dec); - - return res; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (dec, "query failed"); - goto done; - } -} - -static gboolean -theora_dec_sink_query (GstPad * pad, GstQuery * query) -{ - gboolean res = FALSE; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - if (!(res = - theora_dec_sink_convert (pad, src_fmt, src_val, &dest_fmt, - &dest_val))) - goto error; - - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - -error: - return res; -} - -static gboolean -theora_dec_src_event (GstPad * pad, GstEvent * event) -{ - gboolean res = TRUE; - GstTheoraDec *dec; - - dec = GST_THEORA_DEC (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - { - GstFormat format, tformat; - gdouble rate; - GstEvent *real_seek; - GstSeekFlags flags; - GstSeekType cur_type, stop_type; - gint64 cur, stop; - gint64 tcur, tstop; - - gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, - &stop_type, &stop); - gst_event_unref (event); - - /* we have to ask our peer to seek to time here as we know - * nothing about how to generate a granulepos from the src - * formats or anything. - * - * First bring the requested format to time - */ - tformat = GST_FORMAT_TIME; - if (!(res = theora_dec_src_convert (pad, format, cur, &tformat, &tcur))) - goto convert_error; - if (!(res = theora_dec_src_convert (pad, format, stop, &tformat, &tstop))) - goto convert_error; - - /* then seek with time on the peer */ - real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME, - flags, cur_type, tcur, stop_type, tstop); - - res = gst_pad_push_event (dec->sinkpad, real_seek); - break; - } - case GST_EVENT_QOS: - { - gdouble proportion; - GstClockTimeDiff diff; - GstClockTime timestamp; - - gst_event_parse_qos (event, &proportion, &diff, ×tamp); - - /* we cannot randomly skip frame decoding since we don't have - * B frames. we can however use the timestamp and diff to not - * push late frames. This would at least save us the time to - * crop/memcpy the data. */ - GST_OBJECT_LOCK (dec); - dec->proportion = proportion; - dec->earliest_time = timestamp + diff; - GST_OBJECT_UNLOCK (dec); - - GST_DEBUG_OBJECT (dec, "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT, - GST_TIME_ARGS (timestamp), diff); - - res = gst_pad_push_event (dec->sinkpad, event); - break; - } - default: - res = gst_pad_push_event (dec->sinkpad, event); - break; - } -done: - gst_object_unref (dec); - - return res; - - /* ERRORS */ -convert_error: - { - GST_DEBUG_OBJECT (dec, "could not convert format"); - goto done; - } -} - -static gboolean -theora_dec_sink_event (GstPad * pad, GstEvent * event) -{ - gboolean ret = FALSE; - GstTheoraDec *dec; - - dec = GST_THEORA_DEC (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (dec, "handling event"); - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - ret = gst_pad_push_event (dec->srcpad, event); - break; - case GST_EVENT_FLUSH_STOP: - gst_theora_dec_reset (dec); - ret = gst_pad_push_event (dec->srcpad, event); - break; - case GST_EVENT_EOS: - ret = gst_pad_push_event (dec->srcpad, event); - break; - case GST_EVENT_NEWSEGMENT: - { - gboolean update; - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); - - /* we need TIME format */ - if (format != GST_FORMAT_TIME) - goto newseg_wrong_format; - - /* now configure the values */ - gst_segment_set_newsegment_full (&dec->segment, update, - rate, arate, format, start, stop, time); - - /* We don't forward this unless/until the decoder is initialised */ - if (dec->have_header) { - ret = gst_pad_push_event (dec->srcpad, event); - dec->sent_newsegment = TRUE; - } else { - gst_event_unref (event); - ret = TRUE; - } - break; - } - default: - ret = gst_pad_push_event (dec->srcpad, event); - break; - } -done: - gst_object_unref (dec); - - return ret; - - /* ERRORS */ -newseg_wrong_format: - { - GST_DEBUG_OBJECT (dec, "received non TIME newsegment"); - gst_event_unref (event); - goto done; - } -} - -static GstFlowReturn -theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet) -{ - gchar *encoder = NULL; - GstBuffer *buf; - GstTagList *list; - - GST_DEBUG_OBJECT (dec, "parsing comment packet"); - - buf = gst_buffer_new_and_alloc (packet->bytes); - memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes); - - list = - gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\201theora", 7, - &encoder); - - gst_buffer_unref (buf); - - if (!list) { - GST_ERROR_OBJECT (dec, "couldn't decode comments"); - list = gst_tag_list_new (); - } - if (encoder) { - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - GST_TAG_ENCODER, encoder, NULL); - g_free (encoder); - } - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - GST_TAG_ENCODER_VERSION, dec->info.version_major, - GST_TAG_VIDEO_CODEC, "Theora", NULL); - - if (dec->info.target_bitrate > 0) { - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - GST_TAG_BITRATE, dec->info.target_bitrate, - GST_TAG_NOMINAL_BITRATE, dec->info.target_bitrate, NULL); - } - - dec->tags = list; - - return GST_FLOW_OK; -} - -static GstFlowReturn -theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet) -{ - GstCaps *caps; - gint par_num, par_den; - GstFlowReturn ret = GST_FLOW_OK; - gboolean eret; - GstEvent *event; - guint32 bitstream_version; - - GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d", - dec->info.fps_numerator, dec->info.fps_denominator, - dec->info.aspect_numerator, dec->info.aspect_denominator); - - /* calculate par - * the info.aspect_* values reflect PAR; - * 0:0 is allowed and can be interpreted as 1:1, so correct for it */ - par_num = dec->info.aspect_numerator; - par_den = dec->info.aspect_denominator; - if (par_num == 0 && par_den == 0) { - par_num = par_den = 1; - } - /* theora has: - * - * width/height : dimension of the encoded frame - * frame_width/frame_height : dimension of the visible part - * offset_x/offset_y : offset in encoded frame where visible part starts - */ - GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.width, - dec->info.height, par_num, par_den); - GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d", - dec->info.frame_width, dec->info.frame_height, - dec->info.offset_x, dec->info.offset_y); - if (dec->info.pixelformat != OC_PF_420) { - GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, - (NULL), ("pixel formats other than 4:2:0 not yet supported")); - - return GST_FLOW_ERROR; - } - - if (dec->crop) { - /* add black borders to make width/height/offsets even. we need this because - * we cannot express an offset to the peer plugin. */ - dec->width = - GST_ROUND_UP_2 (dec->info.frame_width + (dec->info.offset_x & 1)); - dec->height = - GST_ROUND_UP_2 (dec->info.frame_height + (dec->info.offset_y & 1)); - dec->offset_x = dec->info.offset_x & ~1; - dec->offset_y = dec->info.offset_y & ~1; - } else { - /* no cropping, use the encoded dimensions */ - dec->width = dec->info.width; - dec->height = dec->info.height; - dec->offset_x = 0; - dec->offset_y = 0; - } - - dec->granule_shift = _theora_ilog (dec->info.keyframe_frequency_force - 1); - - /* With libtheora-1.0beta1 the granulepos scheme was changed: - * where earlier the granulepos refered to the index/beginning - * of a frame, it now refers to the end, which matches the use - * in vorbis/speex. We check the bitstream version from the header so - * we know which way to interpret the incoming granuepos - */ - bitstream_version = (dec->info.version_major << 16) | - (dec->info.version_minor << 8) | dec->info.version_subminor; - dec->is_old_bitstream = (bitstream_version <= 0x00030200); - - GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d", - dec->width, dec->height, dec->offset_x, dec->offset_y); - - /* done */ - theora_decode_init (&dec->state, &dec->info); - - caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), - "framerate", GST_TYPE_FRACTION, - dec->info.fps_numerator, dec->info.fps_denominator, - "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den, - "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT, dec->height, NULL); - gst_pad_set_caps (dec->srcpad, caps); - gst_caps_unref (caps); - - dec->have_header = TRUE; - if (!dec->sent_newsegment) { - GST_DEBUG_OBJECT (dec, "Sending newsegment event"); - - event = gst_event_new_new_segment_full (FALSE, - dec->segment.rate, dec->segment.applied_rate, - dec->segment.format, dec->segment.start, dec->segment.stop, - dec->segment.time); - eret = gst_pad_push_event (dec->srcpad, event); - if (!eret) - ret = GST_FLOW_ERROR; - dec->sent_newsegment = TRUE; - } - - if (dec->tags) { - gst_element_found_tags_for_pad (GST_ELEMENT_CAST (dec), dec->srcpad, - dec->tags); - dec->tags = NULL; - } - - return ret; -} - -static GstFlowReturn -theora_handle_header_packet (GstTheoraDec * dec, ogg_packet * packet) -{ - GstFlowReturn res; - - GST_DEBUG_OBJECT (dec, "parsing header packet"); - - if (theora_decode_header (&dec->info, &dec->comment, packet)) - goto header_read_error; - - switch (packet->packet[0]) { - case 0x81: - res = theora_handle_comment_packet (dec, packet); - break; - case 0x82: - res = theora_handle_type_packet (dec, packet); - break; - default: - /* ignore */ - g_warning ("unknown theora header packet found"); - case 0x80: - /* nothing special, this is the identification header */ - res = GST_FLOW_OK; - break; - } - return res; - - /* ERRORS */ -header_read_error: - { - GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, - (NULL), ("couldn't read header packet")); - return GST_FLOW_ERROR; - } -} - -/* returns TRUE if buffer is within segment, else FALSE. - * if Buffer is on segment border, it's timestamp and duration will be clipped */ -static gboolean -clip_buffer (GstTheoraDec * dec, GstBuffer * buf) -{ - gboolean res = TRUE; - GstClockTime in_ts, in_dur, stop; - gint64 cstart, cstop; - - in_ts = GST_BUFFER_TIMESTAMP (buf); - in_dur = GST_BUFFER_DURATION (buf); - - GST_LOG_OBJECT (dec, - "timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT, - GST_TIME_ARGS (in_ts), GST_TIME_ARGS (in_dur)); - - /* can't clip without TIME segment */ - if (dec->segment.format != GST_FORMAT_TIME) - goto beach; - - /* we need a start time */ - if (!GST_CLOCK_TIME_IS_VALID (in_ts)) - goto beach; - - /* generate valid stop, if duration unknown, we have unknown stop */ - stop = - GST_CLOCK_TIME_IS_VALID (in_dur) ? (in_ts + in_dur) : GST_CLOCK_TIME_NONE; - - /* now clip */ - if (!(res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME, - in_ts, stop, &cstart, &cstop))) - goto beach; - - /* update timestamp and possibly duration if the clipped stop time is - * valid */ - GST_BUFFER_TIMESTAMP (buf) = cstart; - if (GST_CLOCK_TIME_IS_VALID (cstop)) - GST_BUFFER_DURATION (buf) = cstop - cstart; - -beach: - GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : "")); - return res; -} - -/* FIXME, this needs to be moved to the demuxer */ -static GstFlowReturn -theora_dec_push_forward (GstTheoraDec * dec, GstBuffer * buf) -{ - GstFlowReturn result = GST_FLOW_OK; - GstClockTime outtime = GST_BUFFER_TIMESTAMP (buf); - - if (outtime == GST_CLOCK_TIME_NONE) { - dec->queued = g_list_append (dec->queued, buf); - GST_DEBUG_OBJECT (dec, "queued buffer"); - } else { - if (dec->queued) { - gint64 size; - GList *walk; - - GST_DEBUG_OBJECT (dec, "first buffer with time %" GST_TIME_FORMAT, - GST_TIME_ARGS (outtime)); - - size = g_list_length (dec->queued); - for (walk = dec->queued; walk; walk = g_list_next (walk)) { - GstBuffer *buffer = GST_BUFFER (walk->data); - GstClockTime time; - - time = outtime - gst_util_uint64_scale_int (size * GST_SECOND, - dec->info.fps_denominator, dec->info.fps_numerator); - - GST_DEBUG_OBJECT (dec, "patch buffer %lld %lld", size, time); - GST_BUFFER_TIMESTAMP (buffer) = time; - /* Next timestamp - this one is duration */ - GST_BUFFER_DURATION (buffer) = - (outtime - gst_util_uint64_scale_int ((size - 1) * GST_SECOND, - dec->info.fps_denominator, dec->info.fps_numerator)) - time; - - if (dec->discont) { - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); - dec->discont = FALSE; - } - /* ignore the result.. */ - if (clip_buffer (dec, buffer)) - gst_pad_push (dec->srcpad, buffer); - else - gst_buffer_unref (buffer); - size--; - } - g_list_free (dec->queued); - dec->queued = NULL; - } - if (dec->discont) { - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - dec->discont = FALSE; - } - if (clip_buffer (dec, buf)) - result = gst_pad_push (dec->srcpad, buf); - else - gst_buffer_unref (buf); - } - return result; -} - -static GstFlowReturn -theora_dec_push_reverse (GstTheoraDec * dec, GstBuffer * buf) -{ - GstFlowReturn result = GST_FLOW_OK; - - dec->queued = g_list_prepend (dec->queued, buf); - - return result; -} - -static GstFlowReturn -theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet, - GstClockTime outtime) -{ - /* normal data packet */ - yuv_buffer yuv; - GstBuffer *out; - guint i; - gboolean keyframe; - gint out_size; - gint stride_y, stride_uv; - gint width, height; - gint cwidth, cheight; - GstFlowReturn result; - - if (G_UNLIKELY (!dec->have_header)) - goto not_initialized; - - /* the second most significant bit of the first data byte is cleared - * for keyframes. We can only check it if it's not a zero-length packet. */ - keyframe = packet->bytes && ((packet->packet[0] & 0x40) == 0); - if (G_UNLIKELY (keyframe)) { - GST_DEBUG_OBJECT (dec, "we have a keyframe"); - dec->need_keyframe = FALSE; - } else if (G_UNLIKELY (dec->need_keyframe)) { - goto dropping; - } - - GST_DEBUG_OBJECT (dec, "parsing data packet"); - - /* this does the decoding */ - if (G_UNLIKELY (theora_decode_packetin (&dec->state, packet))) - goto decode_error; - - if (outtime != -1) { - gboolean need_skip; - GstClockTime qostime; - - /* qos needs to be done on running time */ - qostime = gst_segment_to_running_time (&dec->segment, GST_FORMAT_TIME, - outtime); - - GST_OBJECT_LOCK (dec); - /* check for QoS, don't perform the last steps of getting and - * pushing the buffers that are known to be late. */ - /* FIXME, we can also entirely skip decoding if the next valid buffer is - * known to be after a keyframe (using the granule_shift) */ - need_skip = dec->earliest_time != -1 && qostime <= dec->earliest_time; - GST_OBJECT_UNLOCK (dec); - - if (need_skip) - goto dropping_qos; - } - - /* this does postprocessing and set up the decoded frame - * pointers in our yuv variable */ - if (G_UNLIKELY (theora_decode_YUVout (&dec->state, &yuv) < 0)) - goto no_yuv; - - if (G_UNLIKELY ((yuv.y_width != dec->info.width) - || (yuv.y_height != dec->info.height))) - goto wrong_dimensions; - - width = dec->width; - height = dec->height; - cwidth = width / 2; - cheight = height / 2; - - /* should get the stride from the caps, for now we round up to the nearest - * multiple of 4 because some element needs it. chroma needs special - * treatment, see videotestsrc. */ - stride_y = GST_ROUND_UP_4 (width); - stride_uv = GST_ROUND_UP_8 (width) / 2; - - out_size = stride_y * height + stride_uv * cheight * 2; - - /* now copy over the area contained in offset_x,offset_y, - * frame_width, frame_height */ - result = - gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE, - out_size, GST_PAD_CAPS (dec->srcpad), &out); - if (G_UNLIKELY (result != GST_FLOW_OK)) - goto no_buffer; - - /* copy the visible region to the destination. This is actually pretty - * complicated and gstreamer doesn't support all the needed caps to do this - * correctly. For example, when we have an odd offset, we should only combine - * 1 row/column of luma samples with one chroma sample in colorspace conversion. - * We compensate for this by adding a black border around the image when the - * offset or size is odd (see above). - */ - { - guchar *dest_y, *src_y; - guchar *dest_u, *src_u; - guchar *dest_v, *src_v; - gint offset; - - dest_y = GST_BUFFER_DATA (out); - dest_u = dest_y + stride_y * height; - dest_v = dest_u + stride_uv * cheight; - - src_y = yuv.y + dec->offset_x + dec->offset_y * yuv.y_stride; - - for (i = 0; i < height; i++) { - memcpy (dest_y, src_y, width); - - dest_y += stride_y; - src_y += yuv.y_stride; - } - - offset = dec->offset_x / 2 + dec->offset_y / 2 * yuv.uv_stride; - - src_u = yuv.u + offset; - src_v = yuv.v + offset; - - for (i = 0; i < cheight; i++) { - memcpy (dest_u, src_u, cwidth); - memcpy (dest_v, src_v, cwidth); - - dest_u += stride_uv; - src_u += yuv.uv_stride; - dest_v += stride_uv; - src_v += yuv.uv_stride; - } - } - - GST_BUFFER_OFFSET (out) = dec->frame_nr; - if (dec->frame_nr != -1) - dec->frame_nr++; - GST_BUFFER_OFFSET_END (out) = dec->frame_nr; - if (dec->granulepos != -1) { - gint64 cf = _theora_granule_frame (dec, dec->granulepos) + 1; - - GST_BUFFER_DURATION (out) = gst_util_uint64_scale_int (cf * GST_SECOND, - dec->info.fps_denominator, dec->info.fps_numerator) - outtime; - } else { - GST_BUFFER_DURATION (out) = - gst_util_uint64_scale_int (GST_SECOND, dec->info.fps_denominator, - dec->info.fps_numerator); - } - GST_BUFFER_TIMESTAMP (out) = outtime; - - if (dec->segment.rate >= 0.0) - result = theora_dec_push_forward (dec, out); - else - result = theora_dec_push_reverse (dec, out); - - return result; - - /* ERRORS */ -not_initialized: - { - GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, - (NULL), ("no header sent yet")); - return GST_FLOW_ERROR; - } -dropping: - { - GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe"); - dec->discont = TRUE; - return GST_FLOW_OK; - } -dropping_qos: - { - if (dec->frame_nr != -1) - dec->frame_nr++; - dec->discont = TRUE; - GST_WARNING_OBJECT (dec, "dropping frame because of QoS"); - return GST_FLOW_OK; - } -decode_error: - { - GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, - (NULL), ("theora decoder did not decode data packet")); - return GST_FLOW_ERROR; - } -no_yuv: - { - GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, - (NULL), ("couldn't read out YUV image")); - return GST_FLOW_ERROR; - } -wrong_dimensions: - { - GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT, - (NULL), ("dimensions of image do not match header")); - return GST_FLOW_ERROR; - } -no_buffer: - { - GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s", - gst_flow_get_name (result)); - return result; - } -} - -static GstFlowReturn -theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf) -{ - ogg_packet packet; - GstFlowReturn result = GST_FLOW_OK; - - /* make ogg_packet out of the buffer */ - packet.packet = GST_BUFFER_DATA (buf); - packet.bytes = GST_BUFFER_SIZE (buf); - packet.granulepos = GST_BUFFER_OFFSET_END (buf); - packet.packetno = 0; /* we don't really care */ - packet.b_o_s = dec->have_header ? 0 : 1; - /* EOS does not matter for the decoder */ - packet.e_o_s = 0; - - if (dec->have_header) { - if (packet.granulepos != -1) { - dec->granulepos = packet.granulepos; - dec->last_timestamp = _theora_granule_start_time (dec, packet.granulepos); - } else if (dec->last_timestamp != -1) { - dec->last_timestamp = _theora_granule_start_time (dec, dec->granulepos); - } - if (dec->last_timestamp == -1 && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) - dec->last_timestamp = GST_BUFFER_TIMESTAMP (buf); - } else { - dec->last_timestamp = -1; - } - - GST_DEBUG_OBJECT (dec, "header=%02x packetno=%lld, granule pos=%" - G_GINT64_FORMAT ", outtime=%" GST_TIME_FORMAT, - packet.bytes ? packet.packet[0] : -1, packet.packetno, packet.granulepos, - GST_TIME_ARGS (dec->last_timestamp)); - - /* switch depending on packet type. A zero byte packet is always a data - * packet; we don't dereference it in that case. */ - if (packet.bytes && packet.packet[0] & 0x80) { - if (dec->have_header) { - GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header"); - goto done; - } - result = theora_handle_header_packet (dec, &packet); - } else { - result = theora_handle_data_packet (dec, &packet, dec->last_timestamp); - } - -done: - /* interpolate granule pos */ - dec->granulepos = _inc_granulepos (dec, dec->granulepos); - - return result; -} - -/* For reverse playback we use a technique that can be used for - * any keyframe based video codec. - * - * Input: - * Buffer decoding order: 7 8 9 4 5 6 1 2 3 EOS - * Keyframe flag: K K - * Discont flag: D D D - * - * - Each Discont marks a discont in the decoding order. - * - The keyframes mark where we can start decoding. - * - * First we prepend incomming buffers to the gather queue, whenever we receive - * a discont, we flush out the gather queue. - * - * The above data will be accumulated in the gather queue like this: - * - * gather queue: 9 8 7 - * D - * - * Whe buffer 4 is received (with a DISCONT), we flush the gather queue like - * this: - * - * while (gather) - * take head of queue and prepend to decode queue. - * if we copied a keyframe, decode the decode queue. - * - * After we flushed the gather queue, we add 4 to the (now empty) gather queue. - * We get the following situation: - * - * gather queue: 4 - * decode queue: 7 8 9 - * - * After we received 5 (Keyframe) and 6: - * - * gather queue: 6 5 4 - * decode queue: 7 8 9 - * - * When we receive 1 (DISCONT) which triggers a flush of the gather queue: - * - * Copy head of the gather queue (6) to decode queue: - * - * gather queue: 5 4 - * decode queue: 6 7 8 9 - * - * Copy head of the gather queue (5) to decode queue. This is a keyframe so we - * can start decoding. - * - * gather queue: 4 - * decode queue: 5 6 7 8 9 - * - * Decode frames in decode queue, store raw decoded data in output queue, we - * can take the head of the decode queue and prepend the decoded result in the - * output queue: - * - * gather queue: 4 - * decode queue: - * output queue: 9 8 7 6 5 - * - * Now output all the frames in the output queue, picking a frame from the - * head of the queue. - * - * Copy head of the gather queue (4) to decode queue, we flushed the gather - * queue and can now store input buffer in the gather queue: - * - * gather queue: 1 - * decode queue: 4 - * - * When we receive EOS, the queue looks like: - * - * gather queue: 3 2 1 - * decode queue: 4 - * - * Fill decode queue, first keyframe we copy is 2: - * - * gather queue: 1 - * decode queue: 2 3 4 - * - * Decoded output: - * - * gather queue: 1 - * decode queue: - * output queue: 4 3 2 - * - * Leftover buffer 1 cannot be decoded and must be discarded. - */ -static GstFlowReturn -theora_dec_flush_decode (GstTheoraDec * dec) -{ - GstFlowReturn res = GST_FLOW_OK; - - while (dec->decode) { - GstBuffer *buf = GST_BUFFER_CAST (dec->decode->data); - - GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT, - buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); - - /* decode buffer, prepend to output queue */ - res = theora_dec_decode_buffer (dec, buf); - - /* don't need it anymore now */ - gst_buffer_unref (buf); - - dec->decode = g_list_delete_link (dec->decode, dec->decode); - } - while (dec->queued) { - GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data); - - /* iterate ouput queue an push downstream */ - res = gst_pad_push (dec->srcpad, buf); - - dec->queued = g_list_delete_link (dec->queued, dec->queued); - } - - return res; -} - -static GstFlowReturn -theora_dec_chain_reverse (GstTheoraDec * dec, gboolean discont, GstBuffer * buf) -{ - GstFlowReturn res = GST_FLOW_OK; - - /* if we have a discont, move buffers to the decode list */ - if (G_UNLIKELY (discont)) { - GST_DEBUG_OBJECT (dec, "received discont,gathering buffers"); - while (dec->gather) { - GstBuffer *gbuf; - guint8 *data; - - gbuf = GST_BUFFER_CAST (dec->gather->data); - /* remove from the gather list */ - dec->gather = g_list_delete_link (dec->gather, dec->gather); - /* copy to decode queue */ - dec->decode = g_list_prepend (dec->decode, gbuf); - - /* if we copied a keyframe, flush and decode the decode queue */ - data = GST_BUFFER_DATA (gbuf); - if ((data[0] & 0x40) == 0) { - GST_DEBUG_OBJECT (dec, "copied keyframe"); - res = theora_dec_flush_decode (dec); - } - } - } - - /* add buffer to gather queue */ - GST_DEBUG_OBJECT (dec, "gathering buffer %p, size %u", buf, - GST_BUFFER_SIZE (buf)); - dec->gather = g_list_prepend (dec->gather, buf); - - return res; -} - -static GstFlowReturn -theora_dec_chain_forward (GstTheoraDec * dec, gboolean discont, - GstBuffer * buffer) -{ - GstFlowReturn result; - - result = theora_dec_decode_buffer (dec, buffer); - - gst_buffer_unref (buffer); - - return result; -} - -static GstFlowReturn -theora_dec_chain (GstPad * pad, GstBuffer * buf) -{ - GstTheoraDec *dec; - GstFlowReturn res; - gboolean discont; - - dec = GST_THEORA_DEC (gst_pad_get_parent (pad)); - - /* peel of DISCONT flag */ - discont = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT); - - /* resync on DISCONT */ - if (G_UNLIKELY (discont)) { - GST_DEBUG_OBJECT (dec, "received DISCONT buffer"); - dec->need_keyframe = TRUE; - dec->last_timestamp = -1; - dec->granulepos = -1; - dec->discont = TRUE; - } - - if (dec->segment.rate > 0.0) - res = theora_dec_chain_forward (dec, discont, buf); - else - res = theora_dec_chain_reverse (dec, discont, buf); - - gst_object_unref (dec); - - return res; -} - -static GstStateChangeReturn -theora_dec_change_state (GstElement * element, GstStateChange transition) -{ - GstTheoraDec *dec = GST_THEORA_DEC (element); - GstStateChangeReturn ret; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - theora_info_init (&dec->info); - theora_comment_init (&dec->comment); - GST_DEBUG_OBJECT (dec, "Setting have_header to FALSE in READY->PAUSED"); - dec->have_header = FALSE; - gst_theora_dec_reset (dec); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = parent_class->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - theora_clear (&dec->state); - theora_comment_clear (&dec->comment); - theora_info_clear (&dec->info); - gst_theora_dec_reset (dec); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - -static void -theora_dec_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstTheoraDec *dec = GST_THEORA_DEC (object); - - switch (prop_id) { - case ARG_CROP: - dec->crop = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -theora_dec_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstTheoraDec *dec = GST_THEORA_DEC (object); - - switch (prop_id) { - case ARG_CROP: - g_value_set_boolean (value, dec->crop); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/theora/theoraenc.c --- a/gst_plugins_base/ext/theora/theoraenc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1104 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Wim Taymans - * - * 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. - */ - -/** - * SECTION:element-theoraenc - * @see_also: theoradec, oggmux - * - * - * - * This element encodes raw video into a Theora stream. - * Theora is a royalty-free - * video codec maintained by the Xiph.org - * Foundation, based on the VP3 codec. - * - * - * The theora codec internally only supports encoding of images that are a - * multiple of 16 pixels in both X and Y direction. It is however perfectly - * possible to encode images with other dimensions because an arbitrary - * rectangular cropping region can be set up. This element will automatically - * set up a correct cropping region if the dimensions are not multiples of 16 - * pixels. The "border" and "center" properties control how this cropping - * region will be set up. - * - * - * To control the quality of the encoding, the "bitrate" and "quality" - * properties can be used. These two properties are mutualy exclusive. Setting - * the bitrate property will produce a constant bitrate (CBR) stream while - * setting the quality property will produce a variable bitrate (VBR) stream. - * - * Example pipeline - * - * gst-launch -v videotestsrc num-buffers=1000 ! theoraenc ! oggmux ! filesink location=videotestsrc.ogg - * - * This example pipeline will encode a test video source to theora muxed in an - * ogg container. Refer to the theoradec documentation to decode the create - * stream. - * - * - * Last reviewed on 2006-03-01 (0.10.4) - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "gsttheoraenc.h" - -#include -#include /* free */ - -#include - -#define GST_CAT_DEFAULT theoraenc_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -/* With libtheora-1.0beta1 the granulepos scheme was changed: - * where earlier the granulepos refered to the index/beginning - * of a frame, it now refers to the end, which matches the use - * in vorbis/speex. There don't seem to be defines for the - * theora version we're compiling against, so we'll just use - * a run-time check for now. See theora_enc_get_ogg_packet_end_time(). - */ -static gboolean use_old_granulepos; - -#define GST_TYPE_BORDER_MODE (gst_border_mode_get_type()) -static GType -gst_border_mode_get_type (void) -{ - static GType border_mode_type = 0; - static const GEnumValue border_mode[] = { - {BORDER_NONE, "No Border", "none"}, - {BORDER_BLACK, "Black Border", "black"}, - {BORDER_MIRROR, "Mirror image in borders", "mirror"}, - {0, NULL, NULL}, - }; - - if (!border_mode_type) { - border_mode_type = - g_enum_register_static ("GstTheoraEncBorderMode", border_mode); - } - return border_mode_type; -} - -/* taken from theora/lib/toplevel.c */ -static int -_ilog (unsigned int v) -{ - int ret = 0; - - while (v) { - ret++; - v >>= 1; - } - return (ret); -} - -#define THEORA_DEF_CENTER TRUE -#define THEORA_DEF_BORDER BORDER_BLACK -#define THEORA_DEF_BITRATE 0 -#define THEORA_DEF_QUALITY 16 -#define THEORA_DEF_QUICK TRUE -#define THEORA_DEF_KEYFRAME_AUTO TRUE -#define THEORA_DEF_KEYFRAME_FREQ 64 -#define THEORA_DEF_KEYFRAME_FREQ_FORCE 64 -#define THEORA_DEF_KEYFRAME_THRESHOLD 80 -#define THEORA_DEF_KEYFRAME_MINDISTANCE 8 -#define THEORA_DEF_NOISE_SENSITIVITY 1 -#define THEORA_DEF_SHARPNESS 0 -enum -{ - ARG_0, - ARG_CENTER, - ARG_BORDER, - ARG_BITRATE, - ARG_QUALITY, - ARG_QUICK, - ARG_KEYFRAME_AUTO, - ARG_KEYFRAME_FREQ, - ARG_KEYFRAME_FREQ_FORCE, - ARG_KEYFRAME_THRESHOLD, - ARG_KEYFRAME_MINDISTANCE, - ARG_NOISE_SENSITIVITY, - ARG_SHARPNESS, - /* FILL ME */ -}; - -/* this function does a straight granulepos -> timestamp conversion */ -static GstClockTime -granulepos_to_timestamp (GstTheoraEnc * theoraenc, ogg_int64_t granulepos) -{ - guint64 iframe, pframe; - int shift = theoraenc->granule_shift; - - if (granulepos < 0) - return GST_CLOCK_TIME_NONE; - - iframe = granulepos >> shift; - pframe = granulepos - (iframe << shift); - - /* num and den are 32 bit, so we can safely multiply with GST_SECOND */ - return gst_util_uint64_scale ((guint64) (iframe + pframe), - GST_SECOND * theoraenc->info.fps_denominator, - theoraenc->info.fps_numerator); -} - -static const GstElementDetails theora_enc_details = -GST_ELEMENT_DETAILS ("Theora video encoder", - "Codec/Encoder/Video", - "encode raw YUV video to a theora stream", - "Wim Taymans "); - -static GstStaticPadTemplate theora_enc_sink_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw-yuv, " - "format = (fourcc) I420, " - "framerate = (fraction) [0/1, MAX], " - "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]") - ); - -static GstStaticPadTemplate theora_enc_src_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-theora") - ); - -GST_BOILERPLATE (GstTheoraEnc, gst_theora_enc, GstElement, GST_TYPE_ELEMENT); - -static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer); -static GstStateChangeReturn theora_enc_change_state (GstElement * element, - GstStateChange transition); -static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps); -static void theora_enc_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void theora_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void theora_enc_finalize (GObject * object); - -static void -gst_theora_enc_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&theora_enc_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&theora_enc_sink_factory)); - gst_element_class_set_details (element_class, &theora_enc_details); -} - -static void -gst_theora_enc_class_init (GstTheoraEncClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - - gobject_class->set_property = theora_enc_set_property; - gobject_class->get_property = theora_enc_get_property; - gobject_class->finalize = theora_enc_finalize; - - g_object_class_install_property (gobject_class, ARG_CENTER, - g_param_spec_boolean ("center", "Center", - "Center image when sizes not multiple of 16", THEORA_DEF_CENTER, - (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_BORDER, - g_param_spec_enum ("border", "Border", - "Border color to add when sizes not multiple of 16", - GST_TYPE_BORDER_MODE, THEORA_DEF_BORDER, - (GParamFlags) G_PARAM_READWRITE)); - /* general encoding stream options */ - g_object_class_install_property (gobject_class, ARG_BITRATE, - g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)", - 0, 2000, THEORA_DEF_BITRATE, (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_QUALITY, - g_param_spec_int ("quality", "Quality", "Video quality", - 0, 63, THEORA_DEF_QUALITY, (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_QUICK, - g_param_spec_boolean ("quick", "Quick", "Quick encoding", - THEORA_DEF_QUICK, (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_KEYFRAME_AUTO, - g_param_spec_boolean ("keyframe-auto", "Keyframe Auto", - "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO, - (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_KEYFRAME_FREQ, - g_param_spec_int ("keyframe-freq", "Keyframe frequency", - "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ, - (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_KEYFRAME_FREQ_FORCE, - g_param_spec_int ("keyframe-force", "Keyframe force", - "Force keyframe every N frames", 1, 32768, - THEORA_DEF_KEYFRAME_FREQ_FORCE, (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_KEYFRAME_THRESHOLD, - g_param_spec_int ("keyframe-threshold", "Keyframe threshold", - "Keyframe threshold", 0, 32768, THEORA_DEF_KEYFRAME_THRESHOLD, - (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_KEYFRAME_MINDISTANCE, - g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance", - "Keyframe mindistance", 1, 32768, THEORA_DEF_KEYFRAME_MINDISTANCE, - (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_NOISE_SENSITIVITY, - g_param_spec_int ("noise-sensitivity", "Noise sensitivity", - "Noise sensitivity", 0, 32768, THEORA_DEF_NOISE_SENSITIVITY, - (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_SHARPNESS, - g_param_spec_int ("sharpness", "Sharpness", - "Sharpness", 0, 2, THEORA_DEF_SHARPNESS, - (GParamFlags) G_PARAM_READWRITE)); - - gstelement_class->change_state = theora_enc_change_state; - GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder"); - - use_old_granulepos = (theora_version_number () <= 0x00030200); -} - -static void -gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class) -{ - enc->sinkpad = - gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink"); - gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain); - gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event); - gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps); - gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad); - - enc->srcpad = - gst_pad_new_from_static_template (&theora_enc_src_factory, "src"); - gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad); - - enc->center = THEORA_DEF_CENTER; - enc->border = THEORA_DEF_BORDER; - - enc->video_bitrate = THEORA_DEF_BITRATE; - enc->video_quality = THEORA_DEF_QUALITY; - enc->quick = THEORA_DEF_QUICK; - enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO; - enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ; - enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE; - enc->keyframe_threshold = THEORA_DEF_KEYFRAME_THRESHOLD; - enc->keyframe_mindistance = THEORA_DEF_KEYFRAME_MINDISTANCE; - enc->noise_sensitivity = THEORA_DEF_NOISE_SENSITIVITY; - enc->sharpness = THEORA_DEF_SHARPNESS; - - enc->granule_shift = _ilog (enc->info.keyframe_frequency_force - 1); - GST_DEBUG_OBJECT (enc, - "keyframe_frequency_force is %d, granule shift is %d", - enc->info.keyframe_frequency_force, enc->granule_shift); - enc->expected_ts = GST_CLOCK_TIME_NONE; -} - -static void -theora_enc_finalize (GObject * object) -{ - GstTheoraEnc *enc = GST_THEORA_ENC (object); - - GST_DEBUG_OBJECT (enc, "Finalizing"); - theora_clear (&enc->state); - theora_comment_clear (&enc->comment); - theora_info_clear (&enc->info); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -theora_enc_reset (GstTheoraEnc * enc) -{ - theora_clear (&enc->state); - theora_encode_init (&enc->state, &enc->info); -} - -static void -theora_enc_clear (GstTheoraEnc * enc) -{ - enc->packetno = 0; - enc->bytes_out = 0; - enc->granulepos_offset = 0; - enc->timestamp_offset = 0; - - enc->next_ts = GST_CLOCK_TIME_NONE; - enc->next_discont = FALSE; - enc->expected_ts = GST_CLOCK_TIME_NONE; -} - -static gboolean -theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps) -{ - GstStructure *structure = gst_caps_get_structure (caps, 0); - GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad)); - const GValue *par; - gint fps_n, fps_d; - - gst_structure_get_int (structure, "width", &enc->width); - gst_structure_get_int (structure, "height", &enc->height); - gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d); - par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - - theora_info_clear (&enc->info); - theora_info_init (&enc->info); - /* Theora has a divisible-by-sixteen restriction for the encoded video size but - * we can define a visible area using the frame_width/frame_height */ - enc->info_width = enc->info.width = (enc->width + 15) & ~15; - enc->info_height = enc->info.height = (enc->height + 15) & ~15; - enc->info.frame_width = enc->width; - enc->info.frame_height = enc->height; - - /* center image if needed */ - if (enc->center) { - /* make sure offset is even, for easier decoding */ - enc->offset_x = GST_ROUND_UP_2 ((enc->info_width - enc->width) / 2); - enc->offset_y = GST_ROUND_UP_2 ((enc->info_height - enc->height) / 2); - } else { - enc->offset_x = 0; - enc->offset_y = 0; - } - enc->info.offset_x = enc->offset_x; - enc->info.offset_y = enc->offset_y; - - enc->info.fps_numerator = enc->fps_n = fps_n; - enc->info.fps_denominator = enc->fps_d = fps_d; - if (par) { - enc->info.aspect_numerator = gst_value_get_fraction_numerator (par); - enc->info.aspect_denominator = gst_value_get_fraction_denominator (par); - } else { - /* setting them to 0 indicates that the decoder can chose a good aspect - * ratio, defaulting to 1/1 */ - enc->info.aspect_numerator = 0; - enc->info.aspect_denominator = 0; - } - - enc->info.colorspace = OC_CS_UNSPECIFIED; - enc->info.target_bitrate = enc->video_bitrate; - enc->info.quality = enc->video_quality; - - enc->info.dropframes_p = 0; - enc->info.quick_p = (enc->quick ? 1 : 0); - enc->info.keyframe_auto_p = (enc->keyframe_auto ? 1 : 0); - enc->info.keyframe_frequency = enc->keyframe_freq; - enc->info.keyframe_frequency_force = enc->keyframe_force; - enc->info.keyframe_data_target_bitrate = enc->video_bitrate * 1.5; - enc->info.keyframe_auto_threshold = enc->keyframe_threshold; - enc->info.keyframe_mindistance = enc->keyframe_mindistance; - enc->info.noise_sensitivity = enc->noise_sensitivity; - enc->info.sharpness = enc->sharpness; - - /* as done in theora */ - enc->granule_shift = _ilog (enc->info.keyframe_frequency_force - 1); - GST_DEBUG_OBJECT (enc, - "keyframe_frequency_force is %d, granule shift is %d", - enc->info.keyframe_frequency_force, enc->granule_shift); - - theora_enc_reset (enc); - enc->initialised = TRUE; - - gst_object_unref (enc); - - return TRUE; -} - -static guint64 -granulepos_add (guint64 granulepos, guint64 addend, gint shift) -{ - guint64 iframe, pframe; - - iframe = granulepos >> shift; - pframe = granulepos - (iframe << shift); - iframe += addend; - - return (iframe << shift) + pframe; -} - -/* prepare a buffer for transmission by passing data through libtheora */ -static GstFlowReturn -theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet, - GstClockTime timestamp, GstClockTime duration, GstBuffer ** buffer) -{ - GstBuffer *buf; - GstFlowReturn ret = GST_FLOW_OK; - - buf = gst_buffer_new_and_alloc (packet->bytes); - if (!buf) { - GST_WARNING_OBJECT (enc, "Could not allocate buffer"); - ret = GST_FLOW_ERROR; - goto done; - } - - memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes); - gst_buffer_set_caps (buf, GST_PAD_CAPS (enc->srcpad)); - /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its - * time representation */ - GST_BUFFER_OFFSET_END (buf) = - granulepos_add (packet->granulepos, enc->granulepos_offset, - enc->granule_shift); - GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc, - GST_BUFFER_OFFSET_END (buf)); - - GST_BUFFER_TIMESTAMP (buf) = timestamp + enc->timestamp_offset; - GST_BUFFER_DURATION (buf) = duration; - - if (enc->next_discont) { - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - enc->next_discont = FALSE; - } - - /* the second most significant bit of the first data byte is cleared - * for keyframes */ - if ((packet->packet[0] & 0x40) == 0) { - GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT); - } else { - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); - } - enc->packetno++; - -done: - *buffer = buf; - return ret; -} - -/* push out the buffer and do internal bookkeeping */ -static GstFlowReturn -theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer) -{ - GstFlowReturn ret; - - enc->bytes_out += GST_BUFFER_SIZE (buffer); - - ret = gst_pad_push (enc->srcpad, buffer); - - return ret; -} - -static GstFlowReturn -theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet, - GstClockTime timestamp, GstClockTime duration) -{ - GstBuffer *buf; - GstFlowReturn ret; - - ret = theora_buffer_from_packet (enc, packet, timestamp, duration, &buf); - if (ret == GST_FLOW_OK) - ret = theora_push_buffer (enc, buf); - - return ret; -} - -static GstCaps * -theora_set_header_on_caps (GstCaps * caps, GstBuffer * buf1, - GstBuffer * buf2, GstBuffer * buf3) -{ - GstStructure *structure; - GValue array = { 0 }; - GValue value = { 0 }; - - caps = gst_caps_make_writable (caps); - structure = gst_caps_get_structure (caps, 0); - - /* mark buffers */ - GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS); - GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS); - GST_BUFFER_FLAG_SET (buf3, GST_BUFFER_FLAG_IN_CAPS); - - /* Copy buffers, because we can't use the originals - - * it creates a circular refcount with the caps<->buffers */ - buf1 = gst_buffer_copy (buf1); - buf2 = gst_buffer_copy (buf2); - buf3 = gst_buffer_copy (buf3); - - /* put copies of the buffers in a fixed list */ - g_value_init (&array, GST_TYPE_ARRAY); - - g_value_init (&value, GST_TYPE_BUFFER); - gst_value_set_buffer (&value, buf1); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - - g_value_init (&value, GST_TYPE_BUFFER); - gst_value_set_buffer (&value, buf2); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - - g_value_init (&value, GST_TYPE_BUFFER); - gst_value_set_buffer (&value, buf3); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - - gst_structure_set_value (structure, "streamheader", &array); - g_value_unset (&array); - - /* Unref our copies */ - gst_buffer_unref (buf1); - gst_buffer_unref (buf2); - gst_buffer_unref (buf3); - - return caps; -} - -static GstClockTime -theora_enc_get_ogg_packet_end_time (GstTheoraEnc * enc, ogg_packet * op) -{ - ogg_int64_t end_granule; - - /* FIXME: remove this hack once we depend on libtheora >= 1.0beta1 */ - if (G_UNLIKELY (use_old_granulepos)) { - /* This is where we hack around theora's broken idea of what granulepos - * is -- normally we wouldn't need to add the 1, because granulepos - * should be the presentation time of the last sample in the packet, but - * theora starts with 0 instead of 1... (update: this only applies to old - * bitstream/theora versions, this is fixed with bitstream version 3.2.1) */ - end_granule = granulepos_add (op->granulepos, 1, enc->granule_shift); - } else { - end_granule = op->granulepos; - } - return theora_granule_time (&enc->state, end_granule) * GST_SECOND; -} - -static gboolean -theora_enc_sink_event (GstPad * pad, GstEvent * event) -{ - GstTheoraEnc *enc; - ogg_packet op; - gboolean res; - - enc = GST_THEORA_ENC (GST_PAD_PARENT (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - if (enc->initialised) { - /* push last packet with eos flag */ - while (theora_encode_packetout (&enc->state, 1, &op)) { - GstClockTime next_time = - theora_enc_get_ogg_packet_end_time (enc, &op); - - theora_push_packet (enc, &op, enc->next_ts, next_time - enc->next_ts); - enc->next_ts = next_time; - } - } - res = gst_pad_push_event (enc->srcpad, event); - break; - case GST_EVENT_CUSTOM_DOWNSTREAM: - { - const GstStructure *s; - - s = gst_event_get_structure (event); - - if (gst_structure_has_name (s, "GstForceKeyUnit")) { - GstClockTime next_ts; - - /* make sure timestamps increment after resetting the decoder */ - next_ts = enc->next_ts + enc->timestamp_offset; - - theora_enc_reset (enc); - enc->granulepos_offset = - gst_util_uint64_scale (next_ts, enc->fps_n, - GST_SECOND * enc->fps_d); - enc->timestamp_offset = next_ts; - enc->next_ts = 0; - } - res = gst_pad_push_event (enc->srcpad, event); - break; - } - default: - res = gst_pad_push_event (enc->srcpad, event); - break; - } - return res; -} - -static gboolean -theora_enc_is_discontinuous (GstTheoraEnc * enc, GstBuffer * buffer) -{ - GstClockTime ts = GST_BUFFER_TIMESTAMP (buffer); - GstClockTimeDiff max_diff; - gboolean ret = FALSE; - - /* Allow 3/4 a frame off */ - max_diff = (enc->info.fps_denominator * GST_SECOND * 3) / - (enc->info.fps_numerator * 4); - - if (ts != GST_CLOCK_TIME_NONE && enc->expected_ts != GST_CLOCK_TIME_NONE) { - if ((GstClockTimeDiff) (ts - enc->expected_ts) > max_diff) { - GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT - " exceeds expected value %" GST_TIME_FORMAT - " by too much, marking discontinuity", - GST_TIME_ARGS (ts), GST_TIME_ARGS (enc->expected_ts)); - ret = TRUE; - } - } - - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) - enc->expected_ts = ts + GST_BUFFER_DURATION (buffer); - else - enc->expected_ts = GST_CLOCK_TIME_NONE; - - return ret; -} - -static GstFlowReturn -theora_enc_chain (GstPad * pad, GstBuffer * buffer) -{ - GstTheoraEnc *enc; - ogg_packet op; - GstClockTime in_time; - GstFlowReturn ret; - - enc = GST_THEORA_ENC (GST_PAD_PARENT (pad)); - - in_time = GST_BUFFER_TIMESTAMP (buffer); - - if (enc->packetno == 0) { - /* no packets written yet, setup headers */ - GstCaps *caps; - GstBuffer *buf1, *buf2, *buf3; - - enc->granulepos_offset = 0; - enc->timestamp_offset = 0; - - GST_DEBUG_OBJECT (enc, "output headers"); - /* Theora streams begin with three headers; the initial header (with - most of the codec setup parameters) which is mandated by the Ogg - bitstream spec. The second header holds any comment fields. The - third header holds the bitstream codebook. We merely need to - make the headers, then pass them to libtheora one at a time; - libtheora handles the additional Ogg bitstream constraints */ - - /* first packet will get its own page automatically */ - if (theora_encode_header (&enc->state, &op) != 0) - goto encoder_disabled; - - ret = theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE, - GST_CLOCK_TIME_NONE, &buf1); - if (ret != GST_FLOW_OK) { - goto header_buffer_alloc; - } - - /* create the remaining theora headers */ - theora_comment_clear (&enc->comment); - theora_comment_init (&enc->comment); - - if (theora_encode_comment (&enc->comment, &op) != 0) - goto encoder_disabled; - - ret = theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE, - GST_CLOCK_TIME_NONE, &buf2); - /* Theora expects us to put this packet buffer into an ogg page, - * in which case it becomes the ogg library's responsibility to - * free it. Since we're copying and outputting a gst_buffer, - * we need to free it ourselves. */ - if (op.packet) - free (op.packet); - - if (ret != GST_FLOW_OK) { - gst_buffer_unref (buf1); - goto header_buffer_alloc; - } - - if (theora_encode_tables (&enc->state, &op) != 0) - goto encoder_disabled; - - ret = theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE, - GST_CLOCK_TIME_NONE, &buf3); - if (ret != GST_FLOW_OK) { - gst_buffer_unref (buf1); - gst_buffer_unref (buf2); - goto header_buffer_alloc; - } - - /* mark buffers and put on caps */ - caps = gst_pad_get_caps (enc->srcpad); - caps = theora_set_header_on_caps (caps, buf1, buf2, buf3); - GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps); - gst_pad_set_caps (enc->srcpad, caps); - - gst_buffer_set_caps (buf1, caps); - gst_buffer_set_caps (buf2, caps); - gst_buffer_set_caps (buf3, caps); - - gst_caps_unref (caps); - - /* push out the header buffers */ - if ((ret = theora_push_buffer (enc, buf1)) != GST_FLOW_OK) { - gst_buffer_unref (buf2); - gst_buffer_unref (buf3); - goto header_push; - } - if ((ret = theora_push_buffer (enc, buf2)) != GST_FLOW_OK) { - gst_buffer_unref (buf3); - goto header_push; - } - if ((ret = theora_push_buffer (enc, buf3)) != GST_FLOW_OK) { - goto header_push; - } - - enc->granulepos_offset = - gst_util_uint64_scale (in_time, enc->fps_n, GST_SECOND * enc->fps_d); - enc->timestamp_offset = in_time; - enc->next_ts = 0; - } - - { - yuv_buffer yuv; - gint res; - gint y_size; - guint8 *pixels; - - yuv.y_width = enc->info_width; - yuv.y_height = enc->info_height; - yuv.y_stride = enc->info_width; - - yuv.uv_width = enc->info_width / 2; - yuv.uv_height = enc->info_height / 2; - yuv.uv_stride = yuv.uv_width; - - y_size = enc->info_width * enc->info_height; - - if (enc->width == enc->info_width && enc->height == enc->info_height) { - GST_LOG_OBJECT (enc, "no cropping/conversion needed"); - /* easy case, no cropping/conversion needed */ - pixels = GST_BUFFER_DATA (buffer); - - yuv.y = pixels; - yuv.u = yuv.y + y_size; - yuv.v = yuv.u + y_size / 4; - } else { - GstBuffer *newbuf; - gint i; - guchar *dest_y, *src_y; - guchar *dest_u, *src_u; - guchar *dest_v, *src_v; - gint src_y_stride, src_uv_stride; - gint dst_y_stride, dst_uv_stride; - gint width, height; - gint cwidth, cheight; - gint offset_x, right_x, right_border; - - GST_LOG_OBJECT (enc, "cropping/conversion needed for strides"); - /* source width/height */ - width = enc->width; - height = enc->height; - /* soucre chroma width/height */ - cwidth = width / 2; - cheight = height / 2; - - /* source strides as defined in videotestsrc */ - src_y_stride = GST_ROUND_UP_4 (width); - src_uv_stride = GST_ROUND_UP_8 (width) / 2; - - /* destination strides from the real picture width */ - dst_y_stride = enc->info_width; - dst_uv_stride = enc->info_width / 2; - - newbuf = gst_buffer_new_and_alloc (y_size * 3 / 2); - if (!newbuf) { - ret = GST_FLOW_ERROR; - goto no_buffer; - } - GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET_NONE; - gst_buffer_set_caps (newbuf, GST_PAD_CAPS (enc->srcpad)); - - dest_y = yuv.y = GST_BUFFER_DATA (newbuf); - dest_u = yuv.u = yuv.y + y_size; - dest_v = yuv.v = yuv.u + y_size / 4; - - src_y = GST_BUFFER_DATA (buffer); - src_u = src_y + src_y_stride * GST_ROUND_UP_2 (height); - src_v = src_u + src_uv_stride * GST_ROUND_UP_2 (height) / 2; - - if (enc->border != BORDER_NONE) { - /* fill top border */ - for (i = 0; i < enc->offset_y; i++) { - memset (dest_y, 0, dst_y_stride); - dest_y += dst_y_stride; - } - } else { - dest_y += dst_y_stride * enc->offset_y; - } - - offset_x = enc->offset_x; - right_x = width + enc->offset_x; - right_border = dst_y_stride - right_x; - - /* copy Y plane */ - for (i = 0; i < height; i++) { - memcpy (dest_y + offset_x, src_y, width); - if (enc->border != BORDER_NONE) { - memset (dest_y, 0, offset_x); - memset (dest_y + right_x, 0, right_border); - } - - dest_y += dst_y_stride; - src_y += src_y_stride; - } - - if (enc->border != BORDER_NONE) { - /* fill bottom border */ - for (i = height + enc->offset_y; i < enc->info.height; i++) { - memset (dest_y, 0, dst_y_stride); - dest_y += dst_y_stride; - } - - /* fill top border chroma */ - for (i = 0; i < enc->offset_y / 2; i++) { - memset (dest_u, 128, dst_uv_stride); - memset (dest_v, 128, dst_uv_stride); - dest_u += dst_uv_stride; - dest_v += dst_uv_stride; - } - } else { - dest_u += dst_uv_stride * enc->offset_y / 2; - dest_v += dst_uv_stride * enc->offset_y / 2; - } - - offset_x = enc->offset_x / 2; - right_x = cwidth + offset_x; - right_border = dst_uv_stride - right_x; - - /* copy UV planes */ - for (i = 0; i < cheight; i++) { - memcpy (dest_v + offset_x, src_v, cwidth); - memcpy (dest_u + offset_x, src_u, cwidth); - - if (enc->border != BORDER_NONE) { - memset (dest_u, 128, offset_x); - memset (dest_u + right_x, 128, right_border); - memset (dest_v, 128, offset_x); - memset (dest_v + right_x, 128, right_border); - } - - dest_u += dst_uv_stride; - dest_v += dst_uv_stride; - src_u += src_uv_stride; - src_v += src_uv_stride; - } - - if (enc->border != BORDER_NONE) { - /* fill bottom border */ - for (i = cheight + enc->offset_y / 2; i < enc->info_height / 2; i++) { - memset (dest_u, 128, dst_uv_stride); - memset (dest_v, 128, dst_uv_stride); - dest_u += dst_uv_stride; - dest_v += dst_uv_stride; - } - } - - gst_buffer_unref (buffer); - buffer = newbuf; - } - - if (theora_enc_is_discontinuous (enc, buffer)) { - theora_enc_reset (enc); - enc->granulepos_offset = - gst_util_uint64_scale (in_time, enc->fps_n, GST_SECOND * enc->fps_d); - enc->timestamp_offset = in_time; - enc->next_ts = 0; - enc->next_discont = TRUE; - } - - res = theora_encode_YUVin (&enc->state, &yuv); - - ret = GST_FLOW_OK; - while (theora_encode_packetout (&enc->state, 0, &op)) { - GstClockTime next_time = theora_enc_get_ogg_packet_end_time (enc, &op); - - ret = - theora_push_packet (enc, &op, enc->next_ts, next_time - enc->next_ts); - enc->next_ts = next_time; - if (ret != GST_FLOW_OK) - goto data_push; - } - gst_buffer_unref (buffer); - } - - return ret; - - /* ERRORS */ -header_buffer_alloc: - { - gst_buffer_unref (buffer); - return ret; - } -header_push: - { - gst_buffer_unref (buffer); - return ret; - } -no_buffer: - { - return ret; - } -data_push: - { - gst_buffer_unref (buffer); - return ret; - } -encoder_disabled: - { - GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), - ("libtheora has been compiled with the encoder disabled")); - gst_buffer_unref (buffer); - return GST_FLOW_ERROR; - } -} - -static GstStateChangeReturn -theora_enc_change_state (GstElement * element, GstStateChange transition) -{ - GstTheoraEnc *enc; - GstStateChangeReturn ret; - - enc = GST_THEORA_ENC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state"); - theora_info_init (&enc->info); - theora_comment_init (&enc->comment); - enc->packetno = 0; - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = parent_class->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state"); - theora_clear (&enc->state); - theora_comment_clear (&enc->comment); - theora_info_clear (&enc->info); - - theora_enc_clear (enc); - enc->initialised = FALSE; - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - -static void -theora_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstTheoraEnc *enc = GST_THEORA_ENC (object); - - switch (prop_id) { - case ARG_CENTER: - enc->center = g_value_get_boolean (value); - break; - case ARG_BORDER: - enc->border = g_value_get_enum (value); - break; - case ARG_BITRATE: - enc->video_bitrate = g_value_get_int (value) * 1000; - enc->video_quality = 0; - break; - case ARG_QUALITY: - enc->video_quality = g_value_get_int (value); - enc->video_bitrate = 0; - break; - case ARG_QUICK: - enc->quick = g_value_get_boolean (value); - break; - case ARG_KEYFRAME_AUTO: - enc->keyframe_auto = g_value_get_boolean (value); - break; - case ARG_KEYFRAME_FREQ: - enc->keyframe_freq = g_value_get_int (value); - break; - case ARG_KEYFRAME_FREQ_FORCE: - enc->keyframe_force = g_value_get_int (value); - break; - case ARG_KEYFRAME_THRESHOLD: - enc->keyframe_threshold = g_value_get_int (value); - break; - case ARG_KEYFRAME_MINDISTANCE: - enc->keyframe_mindistance = g_value_get_int (value); - break; - case ARG_NOISE_SENSITIVITY: - enc->noise_sensitivity = g_value_get_int (value); - break; - case ARG_SHARPNESS: - enc->sharpness = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -theora_enc_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstTheoraEnc *enc = GST_THEORA_ENC (object); - - switch (prop_id) { - case ARG_CENTER: - g_value_set_boolean (value, enc->center); - break; - case ARG_BORDER: - g_value_set_enum (value, enc->border); - break; - case ARG_BITRATE: - g_value_set_int (value, enc->video_bitrate / 1000); - break; - case ARG_QUALITY: - g_value_set_int (value, enc->video_quality); - break; - case ARG_QUICK: - g_value_set_boolean (value, enc->quick); - break; - case ARG_KEYFRAME_AUTO: - g_value_set_boolean (value, enc->keyframe_auto); - break; - case ARG_KEYFRAME_FREQ: - g_value_set_int (value, enc->keyframe_freq); - break; - case ARG_KEYFRAME_FREQ_FORCE: - g_value_set_int (value, enc->keyframe_force); - break; - case ARG_KEYFRAME_THRESHOLD: - g_value_set_int (value, enc->keyframe_threshold); - break; - case ARG_KEYFRAME_MINDISTANCE: - g_value_set_int (value, enc->keyframe_mindistance); - break; - case ARG_NOISE_SENSITIVITY: - g_value_set_int (value, enc->noise_sensitivity); - break; - case ARG_SHARPNESS: - g_value_set_int (value, enc->sharpness); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/theora/theoraparse.c --- a/gst_plugins_base/ext/theora/theoraparse.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,917 +0,0 @@ -/* GStreamer - * Copyright (C) <2004> Thomas Vander Stichele - * Copyright (C) 2006 Andy Wingo - * - * 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. - */ - -/** - * SECTION:element-theoraparse - * @short_description: parses theora streams - * @see_also: theoradec, oggdemux, vorbisparse - * - * - * - * The theoraparse element will parse the header packets of the Theora - * stream and put them as the streamheader in the caps. This is used in the - * multifdsink case where you want to stream live theora streams to multiple - * clients, each client has to receive the streamheaders first before they can - * consume the theora packets. - * - * - * This element also makes sure that the buffers that it pushes out are properly - * timestamped and that their offset and offset_end are set. The buffers that - * vorbisparse outputs have all of the metadata that oggmux expects to receive, - * which allows you to (for example) remux an ogg/theora file. - * - * - * In addition, this element allows you to fix badly synchronized streams. You - * pass in an array of (granule time, buffer time) synchronization points via - * the synchronization-points GValueArray property, and this element will adjust - * the granulepos values that it outputs. The adjustment will be made by - * offsetting all buffers that it outputs by a specified amount, and updating - * that offset from the value array whenever a keyframe is processed. - * - * Example pipelines - * - * - * gst-launch -v filesrc location=video.ogg ! oggdemux ! theoraparse ! fakesink - * - * This pipeline shows that the streamheader is set in the caps, and that each - * buffer has the timestamp, duration, offset, and offset_end set. - * - * - * - * gst-launch filesrc location=video.ogg ! oggdemux ! vorbisparse \ - * ! oggmux ! filesink location=video-remuxed.ogg - * - * This pipeline shows remuxing. video-remuxed.ogg might not be exactly the same - * as video.ogg, but they should produce exactly the same decoded data. - * - * - * - * Last reviewed on 2006-04-01 (0.10.4.1) - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "gsttheoraparse.h" - -#define GST_CAT_DEFAULT theoraparse_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -static GstElementDetails theora_parse_details = { - "Theora video parser", - "Codec/Parser/Video", - "parse raw theora streams", - "Andy Wingo " -}; - -static GstStaticPadTemplate theora_parse_sink_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-theora") - ); - -static GstStaticPadTemplate theora_parse_src_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-theora") - ); - -enum -{ - PROP_0, - PROP_SYNCHRONIZATION_POINTS -}; - -GST_BOILERPLATE (GstTheoraParse, gst_theora_parse, GstElement, - GST_TYPE_ELEMENT); - -static void theora_parse_dispose (GObject * object); -static void theora_parse_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void theora_parse_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); - -static gboolean theora_parse_src_query (GstPad * pad, GstQuery * query); -static GstFlowReturn theora_parse_chain (GstPad * pad, GstBuffer * buffer); -static GstStateChangeReturn theora_parse_change_state (GstElement * element, - GstStateChange transition); -static gboolean theora_parse_sink_event (GstPad * pad, GstEvent * event); -static gboolean theora_parse_src_query (GstPad * pad, GstQuery * query); - -static void -gst_theora_parse_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&theora_parse_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&theora_parse_sink_factory)); - gst_element_class_set_details (element_class, &theora_parse_details); -} - -static void -gst_theora_parse_class_init (GstTheoraParseClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - - gobject_class->dispose = theora_parse_dispose; - gobject_class->get_property = theora_parse_get_property; - gobject_class->set_property = theora_parse_set_property; - - /** - * GstTheoraParse:sychronization-points - * - * An array of (granuletime, buffertime) pairs - * - * Since: 0.10.10 - */ - g_object_class_install_property (gobject_class, PROP_SYNCHRONIZATION_POINTS, - g_param_spec_value_array ("synchronization-points", - "Synchronization points", - "An array of (granuletime, buffertime) pairs", - g_param_spec_uint64 ("time", "Time", - "Time (either granuletime or buffertime)", 0, G_MAXUINT64, 0, - G_PARAM_READWRITE), (GParamFlags) G_PARAM_READWRITE)); - - gstelement_class->change_state = theora_parse_change_state; - - GST_DEBUG_CATEGORY_INIT (theoraparse_debug, "theoraparse", 0, - "Theora parser"); -} - -static void -gst_theora_parse_init (GstTheoraParse * parse, GstTheoraParseClass * g_class) -{ - parse->sinkpad = - gst_pad_new_from_static_template (&theora_parse_sink_factory, "sink"); - gst_pad_set_chain_function (parse->sinkpad, theora_parse_chain); - gst_pad_set_event_function (parse->sinkpad, theora_parse_sink_event); - gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad); - - parse->srcpad = - gst_pad_new_from_static_template (&theora_parse_src_factory, "src"); - gst_pad_set_query_function (parse->srcpad, theora_parse_src_query); - gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad); -} - -static void -theora_parse_dispose (GObject * object) -{ - GstTheoraParse *parse = GST_THEORA_PARSE (object); - - g_free (parse->times); - parse->times = NULL; - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -theora_parse_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstTheoraParse *parse = GST_THEORA_PARSE (object); - - switch (prop_id) { - case PROP_SYNCHRONIZATION_POINTS: - { - GValueArray *array; - guint i; - - array = g_value_get_boxed (value); - - if (array) { - if (array->n_values % 2) - goto odd_values; - - g_free (parse->times); - parse->times = g_new (GstClockTime, array->n_values); - parse->npairs = array->n_values / 2; - for (i = 0; i < array->n_values; i++) - parse->times[i] = g_value_get_uint64 (&array->values[i]); - } else { - g_free (parse->times); - parse->npairs = 0; - } - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - return; - -odd_values: - { - g_critical ("expected an even number of time values for " - "synchronization-points"); - return; - } -} - -static void -theora_parse_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstTheoraParse *parse = GST_THEORA_PARSE (object); - - switch (prop_id) { - case PROP_SYNCHRONIZATION_POINTS: - { - GValueArray *array = NULL; - guint i; - - array = g_value_array_new (parse->npairs * 2); - - for (i = 0; i < parse->npairs; i++) { - GValue v = { 0, }; - - g_value_init (&v, G_TYPE_UINT64); - g_value_set_uint64 (&v, parse->times[i * 2]); - g_value_array_append (array, &v); - g_value_set_uint64 (&v, parse->times[i * 2 + 1]); - g_value_array_append (array, &v); - g_value_unset (&v); - } - - g_value_set_boxed (value, array); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -theora_parse_set_header_on_caps (GstTheoraParse * parse, GstCaps * caps) -{ - GstBuffer **bufs; - GstStructure *structure; - gint i; - GValue array = { 0 }; - GValue value = { 0 }; - - bufs = parse->streamheader; - structure = gst_caps_get_structure (caps, 0); - g_value_init (&array, GST_TYPE_ARRAY); - - for (i = 0; i < 3; i++) { - g_assert (bufs[i]); - bufs[i] = gst_buffer_make_metadata_writable (bufs[i]); - GST_BUFFER_FLAG_SET (bufs[i], GST_BUFFER_FLAG_IN_CAPS); - - g_value_init (&value, GST_TYPE_BUFFER); - gst_value_set_buffer (&value, bufs[i]); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - } - - gst_structure_set_value (structure, "streamheader", &array); - g_value_unset (&array); -} - -/* FIXME: copy from libtheora, theora should somehow make this available for seeking */ -static int -_theora_ilog (unsigned int v) -{ - int ret = 0; - - while (v) { - ret++; - v >>= 1; - } - return (ret); -} - -/* two tasks to do here: set the streamheader on the caps, and use libtheora to - parse the headers */ -static void -theora_parse_set_streamheader (GstTheoraParse * parse) -{ - GstCaps *caps; - gint i; - guint32 bitstream_version; - - g_assert (!parse->streamheader_received); - - caps = gst_caps_make_writable (gst_pad_get_caps (parse->srcpad)); - theora_parse_set_header_on_caps (parse, caps); - GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps); - gst_pad_set_caps (parse->srcpad, caps); - gst_caps_unref (caps); - - for (i = 0; i < 3; i++) { - ogg_packet packet; - GstBuffer *buf; - - buf = parse->streamheader[i]; - gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad)); - - packet.packet = GST_BUFFER_DATA (buf); - packet.bytes = GST_BUFFER_SIZE (buf); - packet.granulepos = GST_BUFFER_OFFSET_END (buf); - packet.packetno = i + 1; - packet.e_o_s = 0; - theora_decode_header (&parse->info, &parse->comment, &packet); - } - - parse->fps_n = parse->info.fps_numerator; - parse->fps_d = parse->info.fps_denominator; - parse->shift = _theora_ilog (parse->info.keyframe_frequency_force - 1); - - /* With libtheora-1.0beta1 the granulepos scheme was changed: - * where earlier the granulepos refered to the index/beginning - * of a frame, it now refers to the end, which matches the use - * in vorbis/speex. We check the bitstream version from the header so - * we know which way to interpret the incoming granuepos - */ - bitstream_version = (parse->info.version_major << 16) | - (parse->info.version_minor << 8) | parse->info.version_subminor; - parse->is_old_bitstream = (bitstream_version <= 0x00030200); - - parse->streamheader_received = TRUE; -} - -static void -theora_parse_drain_event_queue (GstTheoraParse * parse) -{ - while (parse->event_queue->length) { - GstEvent *event; - - event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue)); - gst_pad_event_default (parse->sinkpad, event); - } -} - -static void -theora_parse_push_headers (GstTheoraParse * parse) -{ - gint i; - - theora_parse_drain_event_queue (parse); - - if (!parse->streamheader_received) - theora_parse_set_streamheader (parse); - - /* ignore return values, we pass along the result of pushing data packets only - */ - for (i = 0; i < 3; i++) - gst_pad_push (parse->srcpad, gst_buffer_ref (parse->streamheader[i])); - - parse->send_streamheader = FALSE; -} - -static void -theora_parse_clear_queue (GstTheoraParse * parse) -{ - while (parse->buffer_queue->length) { - GstBuffer *buf; - - buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); - gst_buffer_unref (buf); - } - while (parse->event_queue->length) { - GstEvent *event; - - event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue)); - gst_buffer_unref (event); - } -} - -static gint64 -make_granulepos (GstTheoraParse * parse, gint64 keyframe, gint64 frame) -{ - if (keyframe == -1) - keyframe = 0; - /* If using newer theora, offset the granulepos by +1, see comment - * in theora_parse_set_streamheader */ - if (!parse->is_old_bitstream) - keyframe += 1; - - g_return_val_if_fail (frame >= keyframe, -1); - g_return_val_if_fail (frame - keyframe < 1 << parse->shift, -1); - - return (keyframe << parse->shift) + (frame - keyframe); -} - -static void -parse_granulepos (GstTheoraParse * parse, gint64 granulepos, - gint64 * keyframe, gint64 * frame) -{ - gint64 kf; - - kf = granulepos >> parse->shift; - /* If using newer theora, offset the granulepos by -1, see comment - * in theora_parse_set_streamheader */ - if (!parse->is_old_bitstream) - kf -= 1; - if (keyframe) - *keyframe = kf; - if (frame) - *frame = kf + (granulepos & ((1 << parse->shift) - 1)); -} - -static gboolean -is_keyframe (GstBuffer * buf) -{ - if (!GST_BUFFER_DATA (buf)) - return FALSE; - if (!GST_BUFFER_SIZE (buf)) - return FALSE; - return ((GST_BUFFER_DATA (buf)[0] & 0x40) == 0); -} - -static void -theora_parse_munge_granulepos (GstTheoraParse * parse, GstBuffer * buf, - gint64 keyframe, gint64 frame) -{ - gint64 frames_diff; - GstClockTimeDiff time_diff; - - if (keyframe == frame) { - gint i; - - /* update granule_offset */ - for (i = 0; i < parse->npairs; i++) { - if (parse->times[i * 2] >= GST_BUFFER_OFFSET (buf)) - break; - } - if (i > 0) { - /* time_diff gets reset below */ - time_diff = parse->times[i * 2 - 1] - parse->times[i * 2 - 2]; - parse->granule_offset = gst_util_uint64_scale (time_diff, - parse->fps_n, parse->fps_d * GST_SECOND); - parse->granule_offset <<= parse->shift; - } - } - - frames_diff = parse->granule_offset >> parse->shift; - time_diff = gst_util_uint64_scale_int (GST_SECOND * frames_diff, - parse->fps_d, parse->fps_n); - - GST_DEBUG_OBJECT (parse, "offsetting theora stream by %" G_GINT64_FORMAT - " frames (%" GST_TIME_FORMAT ")", frames_diff, GST_TIME_ARGS (time_diff)); - - GST_BUFFER_OFFSET_END (buf) += parse->granule_offset; - GST_BUFFER_OFFSET (buf) += time_diff; - GST_BUFFER_TIMESTAMP (buf) += time_diff; -} - -static GstFlowReturn -theora_parse_push_buffer (GstTheoraParse * parse, GstBuffer * buf, - gint64 keyframe, gint64 frame) -{ - - GstClockTime this_time, next_time; - - this_time = gst_util_uint64_scale_int (GST_SECOND * frame, - parse->fps_d, parse->fps_n); - - next_time = gst_util_uint64_scale_int (GST_SECOND * (frame + 1), - parse->fps_d, parse->fps_n); - - GST_BUFFER_OFFSET_END (buf) = make_granulepos (parse, keyframe, frame); - GST_BUFFER_OFFSET (buf) = this_time; - GST_BUFFER_TIMESTAMP (buf) = this_time; - GST_BUFFER_DURATION (buf) = next_time - this_time; - - gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad)); - - if (parse->times) - theora_parse_munge_granulepos (parse, buf, keyframe, frame); - - GST_DEBUG_OBJECT (parse, "pushing buffer with granulepos %" G_GINT64_FORMAT - "|%" G_GINT64_FORMAT, keyframe, frame - keyframe); - - return gst_pad_push (parse->srcpad, buf); -} - -static GstFlowReturn -theora_parse_drain_queue_prematurely (GstTheoraParse * parse) -{ - GstFlowReturn ret = GST_FLOW_OK; - - /* got an EOS event, make sure to push out any buffers that were in the queue - * -- won't normally be the case, but this catches the - * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous - * stream. */ - - GST_DEBUG_OBJECT (parse, "got EOS, draining queue"); - - /* if we get an eos before pushing the streamheaders, drain our events before - * eos */ - theora_parse_drain_event_queue (parse); - - while (!g_queue_is_empty (parse->buffer_queue)) { - GstBuffer *buf; - - buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); - - parse->prev_frame++; - - if (is_keyframe (buf)) - /* we have a keyframe */ - parse->prev_keyframe = parse->prev_frame; - else - GST_BUFFER_FLAGS (buf) |= GST_BUFFER_FLAG_DELTA_UNIT; - - if (parse->prev_keyframe < 0) { - if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) { - parse_granulepos (parse, GST_BUFFER_OFFSET_END (buf), - &parse->prev_keyframe, NULL); - } else { - /* No previous keyframe known; can't extract one from this frame. That - * means we can't do any valid output for this frame, just continue to - * the next frame. - */ - gst_buffer_unref (buf); - continue; - } - } - - ret = theora_parse_push_buffer (parse, buf, parse->prev_keyframe, - parse->prev_frame); - - if (ret != GST_FLOW_OK) - goto done; - } - -done: - return ret; -} - -static GstFlowReturn -theora_parse_drain_queue (GstTheoraParse * parse, gint64 granulepos) -{ - GstFlowReturn ret = GST_FLOW_OK; - gint64 keyframe, prev_frame, frame; - - parse_granulepos (parse, granulepos, &keyframe, &frame); - - prev_frame = frame - g_queue_get_length (parse->buffer_queue); - if (prev_frame < parse->prev_frame) { - GST_WARNING ("jumped %" G_GINT64_FORMAT - " frames backwards! not sure what to do here", - parse->prev_frame - prev_frame); - ret = GST_FLOW_ERROR; - goto done; - } else if (prev_frame > parse->prev_frame) { - GST_INFO ("discontinuity detected (%" G_GINT64_FORMAT - " frames)", prev_frame - parse->prev_frame); - if (keyframe <= prev_frame && keyframe > parse->prev_keyframe) - parse->prev_keyframe = keyframe; - parse->prev_frame = prev_frame; - } - - GST_DEBUG ("draining queue of length %d", - g_queue_get_length (parse->buffer_queue)); - - while (!g_queue_is_empty (parse->buffer_queue)) { - GstBuffer *buf; - - parse->prev_frame++; - g_assert (parse->prev_frame >= 0); - - buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); - - if (is_keyframe (buf)) - /* we have a keyframe */ - parse->prev_keyframe = parse->prev_frame; - else - GST_BUFFER_FLAGS (buf) |= GST_BUFFER_FLAG_DELTA_UNIT; - - ret = theora_parse_push_buffer (parse, buf, parse->prev_keyframe, - parse->prev_frame); - - if (ret != GST_FLOW_OK) - goto done; - } - -done: - return ret; -} - -static GstFlowReturn -theora_parse_queue_buffer (GstTheoraParse * parse, GstBuffer * buf) -{ - GstFlowReturn ret = GST_FLOW_OK; - - buf = gst_buffer_make_metadata_writable (buf); - - g_queue_push_tail (parse->buffer_queue, buf); - - if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) { - if (parse->prev_keyframe < 0) { - parse_granulepos (parse, GST_BUFFER_OFFSET_END (buf), - &parse->prev_keyframe, NULL); - } - ret = theora_parse_drain_queue (parse, GST_BUFFER_OFFSET_END (buf)); - } - - return ret; -} - -static GstFlowReturn -theora_parse_chain (GstPad * pad, GstBuffer * buffer) -{ - GstFlowReturn ret; - GstBuffer *buf; - GstTheoraParse *parse; - - parse = GST_THEORA_PARSE (gst_pad_get_parent (pad)); - - buf = GST_BUFFER (buffer); - parse->packetno++; - - if (parse->packetno <= 3) { - /* if 1 <= packetno <= 3, it's streamheader, - * so put it on the streamheader list and return */ - parse->streamheader[parse->packetno - 1] = buf; - ret = GST_FLOW_OK; - } else { - if (parse->send_streamheader) - theora_parse_push_headers (parse); - - ret = theora_parse_queue_buffer (parse, buf); - } - - gst_object_unref (parse); - - return ret; -} - -static gboolean -theora_parse_queue_event (GstTheoraParse * parse, GstEvent * event) -{ - g_queue_push_tail (parse->event_queue, event); - return TRUE; -} - -static gboolean -theora_parse_sink_event (GstPad * pad, GstEvent * event) -{ - gboolean ret; - GstTheoraParse *parse; - - parse = GST_THEORA_PARSE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_STOP: - theora_parse_clear_queue (parse); - parse->prev_keyframe = -1; - parse->prev_frame = -1; - ret = gst_pad_event_default (pad, event); - break; - case GST_EVENT_EOS: - theora_parse_drain_queue_prematurely (parse); - ret = gst_pad_event_default (pad, event); - break; - default: - if (parse->send_streamheader && GST_EVENT_IS_SERIALIZED (event)) - ret = theora_parse_queue_event (parse, event); - else - ret = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (parse); - - return ret; -} - -static gboolean -theora_parse_src_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = TRUE; - GstTheoraParse *parse; - guint64 scale = 1; - - if (src_format == *dest_format) { - *dest_value = src_value; - return TRUE; - } - - parse = GST_THEORA_PARSE (gst_pad_get_parent (pad)); - - /* we need the info part before we can done something */ - if (!parse->streamheader_received) - goto no_header; - - switch (src_format) { - case GST_FORMAT_BYTES: - switch (*dest_format) { - case GST_FORMAT_DEFAULT: - *dest_value = gst_util_uint64_scale_int (src_value, 2, - parse->info.height * parse->info.width * 3); - break; - case GST_FORMAT_TIME: - /* seems like a rather silly conversion, implement me if you like */ - default: - res = FALSE; - } - break; - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_BYTES: - scale = 3 * (parse->info.width * parse->info.height) / 2; - case GST_FORMAT_DEFAULT: - *dest_value = scale * gst_util_uint64_scale (src_value, - parse->info.fps_numerator, - parse->info.fps_denominator * GST_SECOND); - break; - default: - GST_DEBUG_OBJECT (parse, "cannot convert to format %s", - gst_format_get_name (*dest_format)); - res = FALSE; - } - break; - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_TIME: - *dest_value = gst_util_uint64_scale (src_value, - GST_SECOND * parse->info.fps_denominator, - parse->info.fps_numerator); - break; - case GST_FORMAT_BYTES: - *dest_value = gst_util_uint64_scale_int (src_value, - 3 * parse->info.width * parse->info.height, 2); - break; - default: - res = FALSE; - } - break; - default: - res = FALSE; - } -done: - gst_object_unref (parse); - return res; - - /* ERRORS */ -no_header: - { - GST_DEBUG_OBJECT (parse, "no header yet, cannot convert"); - res = FALSE; - goto done; - } -} - -static gboolean -theora_parse_src_query (GstPad * pad, GstQuery * query) -{ - GstTheoraParse *parse; - - gboolean res = FALSE; - - parse = GST_THEORA_PARSE (gst_pad_get_parent (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - { - gint64 frame, value; - GstFormat my_format, format; - gint64 time; - - frame = parse->prev_frame; - - GST_LOG_OBJECT (parse, - "query %p: we have current frame: %lld", query, frame); - - /* parse format */ - gst_query_parse_position (query, &format, NULL); - - /* and convert to the final format in two steps with time as the - * intermediate step */ - my_format = GST_FORMAT_TIME; - if (!(res = - theora_parse_src_convert (parse->sinkpad, GST_FORMAT_DEFAULT, - frame, &my_format, &time))) - goto error; - - /* fixme: handle segments - time = (time - parse->segment.start) + parse->segment.time; - */ - - GST_LOG_OBJECT (parse, - "query %p: our time: %" GST_TIME_FORMAT " (conv to %s)", - query, GST_TIME_ARGS (time), gst_format_get_name (format)); - - if (!(res = - theora_parse_src_convert (pad, my_format, time, &format, &value))) - goto error; - - gst_query_set_position (query, format, value); - - GST_LOG_OBJECT (parse, - "query %p: we return %lld (format %u)", query, value, format); - - break; - } - case GST_QUERY_DURATION: - /* forward to peer for total */ - if (!(res = gst_pad_query (GST_PAD_PEER (parse->sinkpad), query))) - goto error; - break; - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - if (!(res = - theora_parse_src_convert (pad, src_fmt, src_val, &dest_fmt, - &dest_val))) - goto error; - - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } -done: - gst_object_unref (parse); - - return res; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (parse, "query failed"); - goto done; - } -} - -static GstStateChangeReturn -theora_parse_change_state (GstElement * element, GstStateChange transition) -{ - GstTheoraParse *parse = GST_THEORA_PARSE (element); - GstStateChangeReturn ret; - gint i; - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - theora_info_init (&parse->info); - theora_comment_init (&parse->comment); - parse->packetno = 0; - parse->send_streamheader = TRUE; - parse->buffer_queue = g_queue_new (); - parse->event_queue = g_queue_new (); - parse->prev_keyframe = -1; - parse->prev_frame = -1; - parse->granule_offset = 0; - break; - default: - break; - } - - ret = parent_class->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - theora_info_clear (&parse->info); - theora_comment_clear (&parse->comment); - theora_parse_clear_queue (parse); - g_queue_free (parse->buffer_queue); - g_queue_free (parse->event_queue); - parse->buffer_queue = NULL; - for (i = 0; i < 3; i++) { - if (parse->streamheader[i]) { - gst_buffer_unref (parse->streamheader[i]); - parse->streamheader[i] = NULL; - } - } - parse->streamheader_received = FALSE; - break; - default: - break; - } - - return ret; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/vorbis/vorbis.c --- a/gst_plugins_base/ext/vorbis/vorbis.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gst/tag/tag.h" - -#include "vorbisenc.h" -#include "vorbisdec.h" -#include "vorbisparse.h" -#include "vorbistag.h" - -GST_DEBUG_CATEGORY (vorbisenc_debug); -GST_DEBUG_CATEGORY (vorbisdec_debug); -GST_DEBUG_CATEGORY (vorbisparse_debug); -GST_DEBUG_CATEGORY (vorbistag_debug); - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "vorbisenc", GST_RANK_NONE, - GST_TYPE_VORBISENC)) - return FALSE; - - if (!gst_element_register (plugin, "vorbisdec", GST_RANK_PRIMARY, - gst_vorbis_dec_get_type ())) - return FALSE; - - if (!gst_element_register (plugin, "vorbisparse", GST_RANK_NONE, - gst_vorbis_parse_get_type ())) - return FALSE; - - if (!gst_element_register (plugin, "vorbistag", GST_RANK_NONE, - gst_vorbis_tag_get_type ())) - return FALSE; - - GST_DEBUG_CATEGORY_INIT (vorbisenc_debug, "vorbisenc", 0, - "vorbis encoding element"); - GST_DEBUG_CATEGORY_INIT (vorbisdec_debug, "vorbisdec", 0, - "vorbis decoding element"); - GST_DEBUG_CATEGORY_INIT (vorbisparse_debug, "vorbisparse", 0, - "vorbis parsing element"); - GST_DEBUG_CATEGORY_INIT (vorbistag_debug, "vorbistag", 0, - "vorbis tagging element"); - - gst_tag_register_musicbrainz_tags (); - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "vorbis", - "Vorbis plugin library", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/vorbis/vorbisdec.c --- a/gst_plugins_base/ext/vorbis/vorbisdec.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1408 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Benjamin Otte - * - * 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. - */ - -/** - * SECTION:element-vorbisdec - * @short_description: a decoder that decodes Vorbis to raw audio - * @see_also: vorbisenc, oggdemux - * - * - * - * This element decodes a Vorbis stream to raw float audio. - * Vorbis is a royalty-free - * audio codec maintained by the Xiph.org - * Foundation. - * - * Example pipelines - * - * - * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! alsasink - * - * Decode an Ogg/Vorbis. To create an Ogg/Vorbis file refer to the documentation of vorbisenc. - * - * - * - * Last reviewed on 2006-03-01 (0.10.4) - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "vorbisdec.h" -#include -#include -#include -#include - -GST_DEBUG_CATEGORY_EXTERN (vorbisdec_debug); -#define GST_CAT_DEFAULT vorbisdec_debug - -static const GstElementDetails vorbis_dec_details = -GST_ELEMENT_DETAILS ("Vorbis audio decoder", - "Codec/Decoder/Audio", - "decode raw vorbis streams to float audio", - "Benjamin Otte "); - -static GstStaticPadTemplate vorbis_dec_src_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-float, " - "rate = (int) [ 1, MAX ], " - "channels = (int) [ 1, 256 ], " "endianness = (int) BYTE_ORDER, " -/* no ifdef in macros, please -#ifdef GST_VORBIS_DEC_SEQUENTIAL - "layout = \"sequential\", " -#endif -*/ - "width = (int) 32") - ); - -static GstStaticPadTemplate vorbis_dec_sink_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-vorbis") - ); - -GST_BOILERPLATE (GstVorbisDec, gst_vorbis_dec, GstElement, GST_TYPE_ELEMENT); - -static void vorbis_dec_finalize (GObject * object); -static gboolean vorbis_dec_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn vorbis_dec_chain (GstPad * pad, GstBuffer * buffer); -static GstFlowReturn vorbis_dec_chain_forward (GstVorbisDec * vd, - gboolean discont, GstBuffer * buffer); -static GstStateChangeReturn vorbis_dec_change_state (GstElement * element, - GstStateChange transition); - -static gboolean vorbis_dec_src_event (GstPad * pad, GstEvent * event); -static gboolean vorbis_dec_src_query (GstPad * pad, GstQuery * query); -static gboolean vorbis_dec_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value); - -static gboolean vorbis_dec_sink_query (GstPad * pad, GstQuery * query); - -static void -gst_vorbis_dec_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - GstPadTemplate *src_template, *sink_template; - - src_template = gst_static_pad_template_get (&vorbis_dec_src_factory); - gst_element_class_add_pad_template (element_class, src_template); - - sink_template = gst_static_pad_template_get (&vorbis_dec_sink_factory); - gst_element_class_add_pad_template (element_class, sink_template); - - gst_element_class_set_details (element_class, &vorbis_dec_details); -} - -static void -gst_vorbis_dec_class_init (GstVorbisDecClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - - gobject_class->finalize = vorbis_dec_finalize; - - gstelement_class->change_state = GST_DEBUG_FUNCPTR (vorbis_dec_change_state); -} - -static const GstQueryType * -vorbis_get_query_types (GstPad * pad) -{ - static const GstQueryType vorbis_dec_src_query_types[] = { - GST_QUERY_POSITION, - GST_QUERY_DURATION, - GST_QUERY_CONVERT, - 0 - }; - - return vorbis_dec_src_query_types; -} - -static void -gst_vorbis_dec_init (GstVorbisDec * dec, GstVorbisDecClass * g_class) -{ - dec->sinkpad = gst_pad_new_from_static_template (&vorbis_dec_sink_factory, - "sink"); - - gst_pad_set_event_function (dec->sinkpad, - GST_DEBUG_FUNCPTR (vorbis_dec_sink_event)); - gst_pad_set_chain_function (dec->sinkpad, - GST_DEBUG_FUNCPTR (vorbis_dec_chain)); - gst_pad_set_query_function (dec->sinkpad, - GST_DEBUG_FUNCPTR (vorbis_dec_sink_query)); - gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad); - - dec->srcpad = gst_pad_new_from_static_template (&vorbis_dec_src_factory, - "src"); - - gst_pad_set_event_function (dec->srcpad, - GST_DEBUG_FUNCPTR (vorbis_dec_src_event)); - gst_pad_set_query_type_function (dec->srcpad, - GST_DEBUG_FUNCPTR (vorbis_get_query_types)); - gst_pad_set_query_function (dec->srcpad, - GST_DEBUG_FUNCPTR (vorbis_dec_src_query)); - gst_pad_use_fixed_caps (dec->srcpad); - gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad); - - dec->queued = NULL; - dec->pendingevents = NULL; - dec->taglist = NULL; -} - -static void -vorbis_dec_finalize (GObject * object) -{ - /* Release any possibly allocated libvorbis data. - * _clear functions can safely be called multiple times - */ - GstVorbisDec *vd = GST_VORBIS_DEC (object); - - vorbis_block_clear (&vd->vb); - vorbis_dsp_clear (&vd->vd); - vorbis_comment_clear (&vd->vc); - vorbis_info_clear (&vd->vi); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_vorbis_dec_reset (GstVorbisDec * dec) -{ - dec->cur_timestamp = GST_CLOCK_TIME_NONE; - dec->prev_timestamp = GST_CLOCK_TIME_NONE; - dec->granulepos = -1; - dec->discont = TRUE; - gst_segment_init (&dec->segment, GST_FORMAT_TIME); - - g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->queued); - dec->queued = NULL; - g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->gather); - dec->gather = NULL; - g_list_foreach (dec->decode, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->decode); - dec->decode = NULL; - g_list_foreach (dec->pendingevents, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->pendingevents); - dec->pendingevents = NULL; - - if (dec->taglist) - gst_tag_list_free (dec->taglist); - dec->taglist = NULL; -} - - -static gboolean -vorbis_dec_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = TRUE; - GstVorbisDec *dec; - guint64 scale = 1; - - if (src_format == *dest_format) { - *dest_value = src_value; - return TRUE; - } - - dec = GST_VORBIS_DEC (gst_pad_get_parent (pad)); - - if (!dec->initialized) - goto no_header; - - if (dec->sinkpad == pad && - (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES)) - goto no_format; - - switch (src_format) { - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_BYTES: - scale = sizeof (float) * dec->vi.channels; - case GST_FORMAT_DEFAULT: - *dest_value = - scale * gst_util_uint64_scale_int (src_value, dec->vi.rate, - GST_SECOND); - break; - default: - res = FALSE; - } - break; - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_BYTES: - *dest_value = src_value * sizeof (float) * dec->vi.channels; - break; - case GST_FORMAT_TIME: - *dest_value = - gst_util_uint64_scale_int (src_value, GST_SECOND, dec->vi.rate); - break; - default: - res = FALSE; - } - break; - case GST_FORMAT_BYTES: - switch (*dest_format) { - case GST_FORMAT_DEFAULT: - *dest_value = src_value / (sizeof (float) * dec->vi.channels); - break; - case GST_FORMAT_TIME: - *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND, - dec->vi.rate * sizeof (float) * dec->vi.channels); - break; - default: - res = FALSE; - } - break; - default: - res = FALSE; - } -done: - gst_object_unref (dec); - - return res; - - /* ERRORS */ -no_header: - { - GST_DEBUG_OBJECT (dec, "no header packets received"); - res = FALSE; - goto done; - } -no_format: - { - GST_DEBUG_OBJECT (dec, "formats unsupported"); - res = FALSE; - goto done; - } -} - -static gboolean -vorbis_dec_src_query (GstPad * pad, GstQuery * query) -{ - GstVorbisDec *dec; - gboolean res = FALSE; - - dec = GST_VORBIS_DEC (gst_pad_get_parent (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - { - gint64 granulepos, value; - GstFormat my_format, format; - gint64 time; - - /* we start from the last seen granulepos */ - granulepos = dec->granulepos; - - gst_query_parse_position (query, &format, NULL); - - /* and convert to the final format in two steps with time as the - * intermediate step */ - my_format = GST_FORMAT_TIME; - if (!(res = - vorbis_dec_convert (pad, GST_FORMAT_DEFAULT, granulepos, - &my_format, &time))) - goto error; - - /* correct for the segment values */ - time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time); - - GST_LOG_OBJECT (dec, - "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time)); - - /* and convert to the final format */ - if (!(res = vorbis_dec_convert (pad, my_format, time, &format, &value))) - goto error; - - gst_query_set_position (query, format, value); - - GST_LOG_OBJECT (dec, - "query %p: we return %lld (format %u)", query, value, format); - - break; - } - case GST_QUERY_DURATION: - { - GstPad *peer; - - if (!(peer = gst_pad_get_peer (dec->sinkpad))) { - GST_WARNING_OBJECT (dec, "sink pad %" GST_PTR_FORMAT " is not linked", - dec->sinkpad); - goto error; - } - - res = gst_pad_query (peer, query); - gst_object_unref (peer); - if (!res) - goto error; - - break; - } - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - if (!(res = - vorbis_dec_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val))) - goto error; - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } -done: - gst_object_unref (dec); - - return res; - - /* ERRORS */ -error: - { - GST_WARNING_OBJECT (dec, "error handling query"); - goto done; - } -} - -static gboolean -vorbis_dec_sink_query (GstPad * pad, GstQuery * query) -{ - GstVorbisDec *dec; - gboolean res; - - dec = GST_VORBIS_DEC (gst_pad_get_parent (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - if (!(res = - vorbis_dec_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val))) - goto error; - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - -done: - gst_object_unref (dec); - - return res; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (dec, "error converting value"); - goto done; - } -} - -static gboolean -vorbis_dec_src_event (GstPad * pad, GstEvent * event) -{ - gboolean res = TRUE; - GstVorbisDec *dec; - - dec = GST_VORBIS_DEC (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - { - GstFormat format, tformat; - gdouble rate; - GstEvent *real_seek; - GstSeekFlags flags; - GstSeekType cur_type, stop_type; - gint64 cur, stop; - gint64 tcur, tstop; - - gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, - &stop_type, &stop); - gst_event_unref (event); - - /* we have to ask our peer to seek to time here as we know - * nothing about how to generate a granulepos from the src - * formats or anything. - * - * First bring the requested format to time - */ - tformat = GST_FORMAT_TIME; - if (!(res = vorbis_dec_convert (pad, format, cur, &tformat, &tcur))) - goto convert_error; - if (!(res = vorbis_dec_convert (pad, format, stop, &tformat, &tstop))) - goto convert_error; - - /* then seek with time on the peer */ - real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME, - flags, cur_type, tcur, stop_type, tstop); - - res = gst_pad_push_event (dec->sinkpad, real_seek); - - break; - } - default: - res = gst_pad_push_event (dec->sinkpad, event); - break; - } -done: - gst_object_unref (dec); - - return res; - - /* ERRORS */ -convert_error: - { - GST_DEBUG_OBJECT (dec, "cannot convert start/stop for seek"); - goto done; - } -} - -static gboolean -vorbis_dec_sink_event (GstPad * pad, GstEvent * event) -{ - gboolean ret = FALSE; - GstVorbisDec *dec; - - dec = GST_VORBIS_DEC (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (dec, "handling event"); - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - ret = gst_pad_push_event (dec->srcpad, event); - break; - case GST_EVENT_FLUSH_START: - ret = gst_pad_push_event (dec->srcpad, event); - break; - case GST_EVENT_FLUSH_STOP: - /* here we must clean any state in the decoder */ -#ifdef HAVE_VORBIS_SYNTHESIS_RESTART - vorbis_synthesis_restart (&dec->vd); -#endif - gst_vorbis_dec_reset (dec); - ret = gst_pad_push_event (dec->srcpad, event); - break; - case GST_EVENT_NEWSEGMENT: - { - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - gboolean update; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); - - /* we need time for now */ - if (format != GST_FORMAT_TIME) - goto newseg_wrong_format; - - GST_DEBUG_OBJECT (dec, - "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT - ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, - update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), - GST_TIME_ARGS (time)); - - /* now configure the values */ - gst_segment_set_newsegment_full (&dec->segment, update, - rate, arate, format, start, stop, time); - - if (dec->initialized) - /* and forward */ - ret = gst_pad_push_event (dec->srcpad, event); - else { - /* store it to send once we're initialized */ - dec->pendingevents = g_list_append (dec->pendingevents, event); - ret = TRUE; - } - break; - } - default: - ret = gst_pad_push_event (dec->srcpad, event); - break; - } -done: - gst_object_unref (dec); - - return ret; - - /* ERRORS */ -newseg_wrong_format: - { - GST_DEBUG_OBJECT (dec, "received non TIME newsegment"); - goto done; - } -} - -static GstFlowReturn -vorbis_handle_identification_packet (GstVorbisDec * vd) -{ - GstCaps *caps; - const GstAudioChannelPosition *pos = NULL; - - switch (vd->vi.channels) { - case 1: - case 2: - /* nothing */ - break; - case 3:{ - static const GstAudioChannelPosition pos3[] = { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT - }; - pos = pos3; - break; - } - case 4:{ - static const GstAudioChannelPosition pos4[] = { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT - }; - pos = pos4; - break; - } - case 5:{ - static const GstAudioChannelPosition pos5[] = { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT - }; - pos = pos5; - break; - } - case 6:{ - static const GstAudioChannelPosition pos6[] = { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_LFE - }; - pos = pos6; - break; - } - default: - goto channel_count_error; - } - - caps = gst_caps_new_simple ("audio/x-raw-float", - "rate", G_TYPE_INT, vd->vi.rate, - "channels", G_TYPE_INT, vd->vi.channels, - "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, NULL); - - if (pos) { - gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos); - } - gst_pad_set_caps (vd->srcpad, caps); - gst_caps_unref (caps); - - return GST_FLOW_OK; - - /* ERROR */ -channel_count_error: - { - GST_ELEMENT_ERROR (vd, STREAM, NOT_IMPLEMENTED, (NULL), - ("Unsupported channel count %d", vd->vi.channels)); - return GST_FLOW_ERROR; - } -} - -static GstFlowReturn -vorbis_handle_comment_packet (GstVorbisDec * vd, ogg_packet * packet) -{ - guint bitrate = 0; - gchar *encoder = NULL; - GstTagList *list; - GstBuffer *buf; - - GST_DEBUG_OBJECT (vd, "parsing comment packet"); - - buf = gst_buffer_new_and_alloc (packet->bytes); - GST_BUFFER_DATA (buf) = packet->packet; - - list = - gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\003vorbis", 7, - &encoder); - - vd->taglist = gst_tag_list_merge (vd->taglist, list, GST_TAG_MERGE_REPLACE); - - gst_tag_list_free (list); - gst_buffer_unref (buf); - - if (!vd->taglist) { - GST_ERROR_OBJECT (vd, "couldn't decode comments"); - vd->taglist = gst_tag_list_new (); - } - if (encoder) { - gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_ENCODER, encoder, NULL); - g_free (encoder); - } - gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_ENCODER_VERSION, vd->vi.version, - GST_TAG_AUDIO_CODEC, "Vorbis", NULL); - if (vd->vi.bitrate_nominal > 0) { - gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_NOMINAL_BITRATE, (guint) vd->vi.bitrate_nominal, NULL); - bitrate = vd->vi.bitrate_nominal; - } - if (vd->vi.bitrate_upper > 0) { - gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_MAXIMUM_BITRATE, (guint) vd->vi.bitrate_upper, NULL); - if (!bitrate) - bitrate = vd->vi.bitrate_upper; - } - if (vd->vi.bitrate_lower > 0) { - gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_MINIMUM_BITRATE, (guint) vd->vi.bitrate_lower, NULL); - if (!bitrate) - bitrate = vd->vi.bitrate_lower; - } - if (bitrate) { - gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_BITRATE, (guint) bitrate, NULL); - } - - if (vd->initialized) { - gst_element_found_tags_for_pad (GST_ELEMENT_CAST (vd), vd->srcpad, - vd->taglist); - vd->taglist = NULL; - } else { - /* Only post them as messages for the time being. * - * They will be pushed on the pad once the decoder is initialized */ - gst_element_post_message (GST_ELEMENT_CAST (vd), - gst_message_new_tag (GST_OBJECT (vd), gst_tag_list_copy (vd->taglist))); - } - - return GST_FLOW_OK; -} - -static GstFlowReturn -vorbis_handle_type_packet (GstVorbisDec * vd) -{ - GList *walk; - - g_assert (vd->initialized == FALSE); - - vorbis_synthesis_init (&vd->vd, &vd->vi); - vorbis_block_init (&vd->vd, &vd->vb); - vd->initialized = TRUE; - - if (vd->pendingevents) { - for (walk = vd->pendingevents; walk; walk = g_list_next (walk)) - gst_pad_push_event (vd->srcpad, GST_EVENT_CAST (walk->data)); - g_list_free (vd->pendingevents); - vd->pendingevents = NULL; - } - - if (vd->taglist) { - /* The tags have already been sent on the bus as messages. */ - gst_pad_push_event (vd->srcpad, gst_event_new_tag (vd->taglist)); - vd->taglist = NULL; - } - - return GST_FLOW_OK; -} - -static GstFlowReturn -vorbis_handle_header_packet (GstVorbisDec * vd, ogg_packet * packet) -{ - GstFlowReturn res; - - GST_DEBUG_OBJECT (vd, "parsing header packet"); - - /* Packetno = 0 if the first byte is exactly 0x01 */ - packet->b_o_s = (packet->packet[0] == 0x1) ? 1 : 0; - - if (vorbis_synthesis_headerin (&vd->vi, &vd->vc, packet)) - goto header_read_error; - - switch (packet->packet[0]) { - case 0x01: - res = vorbis_handle_identification_packet (vd); - break; - case 0x03: - res = vorbis_handle_comment_packet (vd, packet); - break; - case 0x05: - res = vorbis_handle_type_packet (vd); - break; - default: - /* ignore */ - g_warning ("unknown vorbis header packet found"); - res = GST_FLOW_OK; - break; - } - return res; - - /* ERRORS */ -header_read_error: - { - GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE, - (NULL), ("couldn't read header packet")); - return GST_FLOW_ERROR; - } -} - -/* These samples can be outside of the float -1.0 -- 1.0 range, this - * is allowed, downstream elements are supposed to clip */ -static void -copy_samples (float *out, float **in, guint samples, gint channels) -{ - gint i, j; - -#ifdef GST_VORBIS_DEC_SEQUENTIAL - for (i = 0; i < channels; i++) { - memcpy (out, in[i], samples * sizeof (float)); - out += samples; - } -#else - for (j = 0; j < samples; j++) { - for (i = 0; i < channels; i++) { - *out++ = in[i][j]; - } - } -#endif -} - -static GstFlowReturn -vorbis_dec_push_forward (GstVorbisDec * dec, GstBuffer * buf) -{ - GstFlowReturn result; - gint64 outoffset, origoffset; - - origoffset = GST_BUFFER_OFFSET (buf); - -again: - outoffset = origoffset; - - if (outoffset == -1) { - dec->queued = g_list_append (dec->queued, buf); - GST_DEBUG_OBJECT (dec, "queued buffer"); - result = GST_FLOW_OK; - } else { - if (G_UNLIKELY (dec->queued)) { - guint size; - GstClockTime ts; - GList *walk; - - GST_DEBUG_OBJECT (dec, "first buffer with offset %lld", outoffset); - ts = gst_util_uint64_scale_int (outoffset, GST_SECOND, dec->vi.rate); - - size = g_list_length (dec->queued); - /* we walk the queued up list in reverse, and set the buffer fields - * calculating backwards */ - for (walk = g_list_last (dec->queued); walk; - walk = g_list_previous (walk)) { - GstBuffer *buffer = GST_BUFFER (walk->data); - guint offset; - - offset = GST_BUFFER_SIZE (buffer) / (sizeof (float) * dec->vi.channels); - - if (outoffset >= offset) - outoffset -= offset; - else { - /* we can't go below 0, this means this first offset was at the eos - * page and we need to clip to it instead */ - GST_DEBUG_OBJECT (dec, "clipping %" G_GINT64_FORMAT, - offset - outoffset); - origoffset += (offset - outoffset); - goto again; - } - - GST_BUFFER_OFFSET (buffer) = outoffset; - GST_BUFFER_TIMESTAMP (buffer) = - gst_util_uint64_scale_int (outoffset, GST_SECOND, dec->vi.rate); - GST_BUFFER_DURATION (buffer) = GST_CLOCK_DIFF (GST_BUFFER_TIMESTAMP - (buffer), ts); - ts = GST_BUFFER_TIMESTAMP (buffer); - GST_DEBUG_OBJECT (dec, "patch buffer %u, offset %" G_GUINT64_FORMAT - ", timestamp %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, - size, outoffset, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buffer))); - size--; - } - for (walk = dec->queued; walk; walk = g_list_next (walk)) { - GstBuffer *buffer = GST_BUFFER (walk->data); - - /* clips to the configured segment, or returns NULL with buffer - * unreffed when the input buffer is completely outside the segment */ - if (!(buffer = gst_audio_buffer_clip (buffer, &dec->segment, - dec->vi.rate, dec->vi.channels * sizeof (float)))) - continue; - - if (dec->discont) { - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); - dec->discont = FALSE; - } - /* ignore the result */ - gst_pad_push (dec->srcpad, buffer); - } - g_list_free (dec->queued); - dec->queued = NULL; - } - - /* clip */ - if (!(buf = gst_audio_buffer_clip (buf, &dec->segment, dec->vi.rate, - dec->vi.channels * sizeof (float)))) - return GST_FLOW_OK; - - if (dec->discont) { - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - dec->discont = FALSE; - } - - result = gst_pad_push (dec->srcpad, buf); - } - - return result; -} - -static GstFlowReturn -vorbis_dec_push_reverse (GstVorbisDec * dec, GstBuffer * buf) -{ - GstFlowReturn result = GST_FLOW_OK; - - dec->queued = g_list_prepend (dec->queued, buf); - - return result; -} - -static GstFlowReturn -vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet) -{ - float **pcm; - guint sample_count; - GstBuffer *out; - GstFlowReturn result; - GstClockTime timestamp = GST_CLOCK_TIME_NONE, nextts; - gint size; - - if (!vd->initialized) - goto not_initialized; - - /* FIXME, we should queue undecoded packets here until we get - * a timestamp, then we reverse timestamp the queued packets and - * clip them, then we decode only the ones we want and don't - * keep decoded data in memory. - * Ideally, of course, the demuxer gives us a valid timestamp on - * the first packet. - */ - - /* normal data packet */ - /* FIXME, we can skip decoding if the packet is outside of the - * segment, this is however not very trivial as we need a previous - * packet to decode the current one so we must be carefull not to - * throw away too much. For now we decode everything and clip right - * before pushing data. */ - if (G_UNLIKELY (vorbis_synthesis (&vd->vb, packet))) - goto could_not_read; - - if (G_UNLIKELY (vorbis_synthesis_blockin (&vd->vd, &vd->vb) < 0)) - goto not_accepted; - - /* assume all goes well here */ - result = GST_FLOW_OK; - - /* count samples ready for reading */ - if ((sample_count = vorbis_synthesis_pcmout (&vd->vd, NULL)) == 0) - goto done; - - GST_LOG_OBJECT (vd, "%d samples ready for reading", sample_count); - size = sample_count * vd->vi.channels * sizeof (float); - - /* alloc buffer for it */ - result = - gst_pad_alloc_buffer_and_set_caps (vd->srcpad, GST_BUFFER_OFFSET_NONE, - size, GST_PAD_CAPS (vd->srcpad), &out); - if (G_UNLIKELY (result != GST_FLOW_OK)) - goto done; - - /* get samples ready for reading now, should be sample_count */ - if (G_UNLIKELY ((vorbis_synthesis_pcmout (&vd->vd, &pcm)) != sample_count)) - goto wrong_samples; - - /* copy samples in buffer */ - copy_samples ((float *) GST_BUFFER_DATA (out), pcm, sample_count, - vd->vi.channels); - - GST_BUFFER_SIZE (out) = size; - - /* this should not overflow */ - GST_BUFFER_DURATION (out) = sample_count * GST_SECOND / vd->vi.rate; - - if (packet->granulepos != -1) - vd->granulepos = packet->granulepos - sample_count; - - if (vd->cur_timestamp != GST_CLOCK_TIME_NONE) { - /* we have incoming timestamps */ - timestamp = vd->cur_timestamp; - GST_DEBUG_OBJECT (vd, - "cur_timestamp: %" GST_TIME_FORMAT " + %" GST_TIME_FORMAT " = %" - GST_TIME_FORMAT, GST_TIME_ARGS (vd->cur_timestamp), - GST_TIME_ARGS (GST_BUFFER_DURATION (out)), - GST_TIME_ARGS (vd->cur_timestamp + GST_BUFFER_DURATION (out))); - vd->cur_timestamp += GST_BUFFER_DURATION (out); - GST_BUFFER_OFFSET (out) = GST_CLOCK_TIME_TO_FRAMES (vd->cur_timestamp, - vd->vi.rate); - GST_BUFFER_OFFSET_END (out) = GST_BUFFER_OFFSET (out) + sample_count; - } else { - /* we have incoming granulepos */ - GST_BUFFER_OFFSET (out) = vd->granulepos; - if (vd->granulepos != -1) { - GST_DEBUG_OBJECT (vd, "granulepos: %" G_GINT64_FORMAT, vd->granulepos); - GST_BUFFER_OFFSET_END (out) = vd->granulepos + sample_count; - timestamp = - gst_util_uint64_scale_int (vd->granulepos, GST_SECOND, vd->vi.rate); - nextts = - gst_util_uint64_scale_int (vd->granulepos + sample_count, - GST_SECOND, vd->vi.rate); - GST_DEBUG_OBJECT (vd, "corresponding timestamp %" GST_TIME_FORMAT, - GST_TIME_ARGS (timestamp)); - /* calculate a nano-second accurate duration */ - GST_BUFFER_DURATION (out) = GST_CLOCK_DIFF (timestamp, nextts); - GST_DEBUG_OBJECT (vd, "set duration %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_DURATION (out))); - } else { - timestamp = -1; - } - } - GST_BUFFER_TIMESTAMP (out) = timestamp; - - if (vd->granulepos != -1) - vd->granulepos += sample_count; - - if (vd->segment.rate >= 0.0) - result = vorbis_dec_push_forward (vd, out); - else - result = vorbis_dec_push_reverse (vd, out); - -done: - vorbis_synthesis_read (&vd->vd, sample_count); - - GST_DEBUG_OBJECT (vd, - "decoded %ld bytes into %d samples, ts %" GST_TIME_FORMAT, packet->bytes, - sample_count, GST_TIME_ARGS (timestamp)); - - /* granulepos is the last sample in the packet */ - if (packet->granulepos != -1) - vd->granulepos = packet->granulepos; - - return result; - - /* ERRORS */ -not_initialized: - { - GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE, - (NULL), ("no header sent yet")); - return GST_FLOW_ERROR; - } -could_not_read: - { - GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE, - (NULL), ("couldn't read data packet")); - return GST_FLOW_ERROR; - } -not_accepted: - { - GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE, - (NULL), ("vorbis decoder did not accept data packet")); - return GST_FLOW_ERROR; - } -wrong_samples: - { - gst_buffer_unref (out); - GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE, - (NULL), ("vorbis decoder reported wrong number of samples")); - return GST_FLOW_ERROR; - } -} - -static GstFlowReturn -vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer) -{ - ogg_packet packet; - GstFlowReturn result = GST_FLOW_OK; - GstClockTime timestamp; - guint64 offset_end; - - timestamp = GST_BUFFER_TIMESTAMP (buffer); - offset_end = GST_BUFFER_OFFSET_END (buffer); - - /* only ogg has granulepos, demuxers of other container formats - * might provide us with timestamps instead (e.g. matroskademux) */ - if (offset_end == GST_BUFFER_OFFSET_NONE && timestamp != GST_CLOCK_TIME_NONE) { - /* we might get multiple consecutive buffers with the same timestamp */ - if (timestamp != vd->prev_timestamp) { - vd->cur_timestamp = timestamp; - vd->prev_timestamp = timestamp; - } - } else { - vd->cur_timestamp = GST_CLOCK_TIME_NONE; - vd->prev_timestamp = GST_CLOCK_TIME_NONE; - } - - /* make ogg_packet out of the buffer */ - packet.packet = GST_BUFFER_DATA (buffer); - packet.bytes = GST_BUFFER_SIZE (buffer); - packet.granulepos = offset_end; - packet.packetno = 0; /* we don't care */ - /* - * FIXME. Is there anyway to know that this is the last packet and - * set e_o_s?? - * Yes there is, keep one packet at all times and only push out when - * you receive a new one. Implement this. - */ - packet.e_o_s = 0; - - /* error out on empty header packets, but just skip empty data packets */ - if (G_UNLIKELY (packet.bytes == 0)) { - if (vd->initialized) - goto empty_buffer; - else - goto empty_header; - } - - GST_DEBUG_OBJECT (vd, "vorbis granule: %" G_GINT64_FORMAT, - (gint64) packet.granulepos); - - /* switch depending on packet type */ - if (packet.packet[0] & 1) { - if (vd->initialized) { - GST_WARNING_OBJECT (vd, "Already initialized, so ignoring header packet"); - goto done; - } - result = vorbis_handle_header_packet (vd, &packet); - } else { - result = vorbis_handle_data_packet (vd, &packet); - } - -done: - return result; - -empty_buffer: - { - /* don't error out here, just ignore the buffer, it's invalid for vorbis - * but not fatal. */ - GST_WARNING_OBJECT (vd, "empty buffer received, ignoring"); - if (packet.granulepos != -1) - vd->granulepos = packet.granulepos; - result = GST_FLOW_OK; - goto done; - } - -/* ERRORS */ -empty_header: - { - GST_ELEMENT_ERROR (vd, STREAM, DECODE, (NULL), ("empty header received")); - result = GST_FLOW_ERROR; - vd->discont = TRUE; - goto done; - } -} - -/* - * Input: - * Buffer decoding order: 7 8 9 4 5 6 3 1 2 EOS - * Discont flag: D D D D - * - * - Each Discont marks a discont in the decoding order. - * - * for vorbis, each buffer is a keyframe when we have the previous - * buffer. This means that to decode buffer 7, we need buffer 6, which - * arrives out of order. - * - * we first gather buffers in the gather queue until we get a DISCONT. We - * prepend each incomming buffer so that they are in reversed order. - * - * gather queue: 9 8 7 - * decode queue: - * output queue: - * - * When a DISCONT is received (buffer 4), we move the gather queue to the - * decode queue. This is simply done be taking the head of the gather queue - * and prepending it to the decode queue. This yields: - * - * gather queue: - * decode queue: 7 8 9 - * output queue: - * - * Then we decode each buffer in the decode queue in order and put the output - * buffer in the output queue. The first buffer (7) will not produce and output - * because it needs the previous buffer (6) which did not arrive yet. This - * yields: - * - * gather queue: - * decode queue: 7 8 9 - * output queue: 9 8 - * - * Then we remove the consumed buffers from the decode queue. Buffer 7 is not - * completely consumed, we need to keep it around for when we receive buffer - * 6. This yields: - * - * gather queue: - * decode queue: 7 - * output queue: 9 8 - * - * Then we accumulate more buffers: - * - * gather queue: 6 5 4 - * decode queue: 7 - * output queue: - * - * prepending to the decode queue on DISCONT yields: - * - * gather queue: - * decode queue: 4 5 6 7 - * output queue: - * - * after decoding and keeping buffer 4: - * - * gather queue: - * decode queue: 4 - * output queue: 7 6 5 - * - * Etc.. - */ -static GstFlowReturn -vorbis_dec_flush_decode (GstVorbisDec * dec) -{ - GstFlowReturn res = GST_FLOW_OK; - GList *walk; - - walk = dec->decode; - - GST_DEBUG_OBJECT (dec, "flushing buffers to decoder"); - - while (walk) { - GList *next; - GstBuffer *buf = GST_BUFFER_CAST (walk->data); - - GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT, - buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); - - next = g_list_next (walk); - - /* decode buffer, prepend to output queue */ - res = vorbis_dec_decode_buffer (dec, buf); - - /* if we generated output, we can discard the buffer, else we - * keep it in the queue */ - if (dec->queued) { - GST_DEBUG_OBJECT (dec, "decoded buffer to %p", dec->queued->data); - dec->decode = g_list_delete_link (dec->decode, walk); - gst_buffer_unref (buf); - } else { - GST_DEBUG_OBJECT (dec, "buffer did not decode, keeping"); - } - walk = next; - } - if (dec->granulepos != -1) { - GstClockTime endts; - - endts = - gst_util_uint64_scale_int (dec->granulepos, GST_SECOND, dec->vi.rate); - - GST_DEBUG_OBJECT (dec, "we have granulepos %" G_GUINT64_FORMAT ", ts %" - GST_TIME_FORMAT, dec->granulepos, GST_TIME_ARGS (endts)); - - while (dec->queued) { - GstBuffer *buf; - guint sample_count; - - buf = GST_BUFFER_CAST (dec->queued->data); - - sample_count = - GST_BUFFER_SIZE (buf) / (dec->vi.channels * sizeof (float)); - - GST_BUFFER_OFFSET_END (buf) = dec->granulepos; - endts = - gst_util_uint64_scale_int (dec->granulepos, GST_SECOND, dec->vi.rate); - dec->granulepos -= sample_count; - GST_BUFFER_OFFSET (buf) = dec->granulepos; - GST_BUFFER_TIMESTAMP (buf) = - gst_util_uint64_scale_int (dec->granulepos, GST_SECOND, dec->vi.rate); - GST_BUFFER_DURATION (buf) = endts - GST_BUFFER_TIMESTAMP (buf); - - /* clip, this will unref the buffer in case of clipping */ - if (!(buf = gst_audio_buffer_clip (buf, &dec->segment, dec->vi.rate, - dec->vi.channels * sizeof (float)))) { - GST_DEBUG_OBJECT (dec, "clipped buffer %p", buf); - goto next; - } - - if (dec->discont) { - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - dec->discont = FALSE; - } - GST_DEBUG_OBJECT (dec, "pushing buffer %p, samples %u, " - "ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, - buf, sample_count, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - - res = gst_pad_push (dec->srcpad, buf); - next: - dec->queued = g_list_delete_link (dec->queued, dec->queued); - } - } else { - GST_DEBUG_OBJECT (dec, "we don't have a granulepos yet, delayed push"); - } - return res; -} - -static GstFlowReturn -vorbis_dec_chain_reverse (GstVorbisDec * vd, gboolean discont, GstBuffer * buf) -{ - GstFlowReturn result = GST_FLOW_OK; - - /* if we have a discont, move buffers to the decode list */ - if (G_UNLIKELY (discont)) { - GST_DEBUG_OBJECT (vd, "received discont"); - while (vd->gather) { - GstBuffer *gbuf; - - gbuf = GST_BUFFER_CAST (vd->gather->data); - /* remove from the gather list */ - vd->gather = g_list_delete_link (vd->gather, vd->gather); - /* copy to decode queue */ - vd->decode = g_list_prepend (vd->decode, gbuf); - } - /* flush and decode the decode queue */ - result = vorbis_dec_flush_decode (vd); - } - - GST_DEBUG_OBJECT (vd, "gathering buffer %p, size %u", buf, - GST_BUFFER_SIZE (buf)); - /* add buffer to gather queue */ - vd->gather = g_list_prepend (vd->gather, buf); - - return result; -} - -static GstFlowReturn -vorbis_dec_chain_forward (GstVorbisDec * vd, gboolean discont, - GstBuffer * buffer) -{ - GstFlowReturn result; - - result = vorbis_dec_decode_buffer (vd, buffer); - - gst_buffer_unref (buffer); - - return result; - -} - -static GstFlowReturn -vorbis_dec_chain (GstPad * pad, GstBuffer * buffer) -{ - GstVorbisDec *vd; - GstFlowReturn result = GST_FLOW_OK; - gboolean discont; - - vd = GST_VORBIS_DEC (gst_pad_get_parent (pad)); - - discont = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT); - - /* resync on DISCONT */ - if (G_UNLIKELY (discont)) { - GST_DEBUG_OBJECT (vd, "received DISCONT buffer"); - vd->granulepos = -1; - vd->cur_timestamp = GST_CLOCK_TIME_NONE; - vd->prev_timestamp = GST_CLOCK_TIME_NONE; -#ifdef HAVE_VORBIS_SYNTHESIS_RESTART - vorbis_synthesis_restart (&vd->vd); -#endif - vd->discont = TRUE; - } - - if (vd->segment.rate >= 0.0) - result = vorbis_dec_chain_forward (vd, discont, buffer); - else - result = vorbis_dec_chain_reverse (vd, discont, buffer); - - gst_object_unref (vd); - - return result; -} - -static GstStateChangeReturn -vorbis_dec_change_state (GstElement * element, GstStateChange transition) -{ - GstVorbisDec *vd = GST_VORBIS_DEC (element); - GstStateChangeReturn res; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - vorbis_info_init (&vd->vi); - vorbis_comment_init (&vd->vc); - vd->initialized = FALSE; - gst_vorbis_dec_reset (vd); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - res = parent_class->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_DEBUG_OBJECT (vd, "PAUSED -> READY, clearing vorbis structures"); - vorbis_block_clear (&vd->vb); - vorbis_dsp_clear (&vd->vd); - vorbis_comment_clear (&vd->vc); - vorbis_info_clear (&vd->vi); - gst_vorbis_dec_reset (vd); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return res; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/vorbis/vorbisdec.h --- a/gst_plugins_base/ext/vorbis/vorbisdec.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* -*- c-basic-offset: 2 -*- - * GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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. - */ - - -#ifndef __GST_VORBIS_DEC_H__ -#define __GST_VORBIS_DEC_H__ - - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_VORBIS_DEC \ - (gst_vorbis_dec_get_type()) -#define GST_VORBIS_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VORBIS_DEC,GstVorbisDec)) -#define GST_VORBIS_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VORBIS_DEC,GstVorbisDecClass)) -#define GST_IS_VORBIS_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBIS_DEC)) -#define GST_IS_VORBIS_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBIS_DEC)) - -typedef struct _GstVorbisDec GstVorbisDec; -typedef struct _GstVorbisDecClass GstVorbisDecClass; - -/** - * GstVorbisDec: - * - * Opaque data structure. - */ -struct _GstVorbisDec { - GstElement element; - - GstPad *sinkpad; - GstPad *srcpad; - - vorbis_dsp_state vd; - vorbis_info vi; - vorbis_comment vc; - vorbis_block vb; - guint64 granulepos; - - gboolean initialized; - - /* list of buffers that need timestamps */ - GList *queued; - /* list of raw output buffers */ - GList *output; - /* gather/decode queues for reverse playback */ - GList *gather; - GList *decode; - - GstSegment segment; - gboolean discont; - - GstClockTime cur_timestamp; /* only used with non-ogg container formats */ - GstClockTime prev_timestamp; /* only used with non-ogg container formats */ - - GList *pendingevents; - GstTagList *taglist; -}; - -struct _GstVorbisDecClass { - GstElementClass parent_class; -}; - -GType gst_vorbis_dec_get_type(void); - -G_END_DECLS - -#endif /* __GST_VORBIS_DEC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/vorbis/vorbisenc.c --- a/gst_plugins_base/ext/vorbis/vorbisenc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1389 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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. - */ - -/** - * SECTION:element-vorbisenc - * @short_description: an encoder that encodes audio to Vorbis - * @see_also: vorbisdec, oggmux - * - * - * - * This element encodes raw float audio into a Vorbis stream. - * Vorbis is a royalty-free - * audio codec maintained by the Xiph.org - * Foundation. - * - * Example pipelines - * - * Encode a test sine signal to Ogg/Vorbis. Note that the resulting file - * will be really small because a sine signal compresses very well. - * - * - * gst-launch -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! vorbisenc ! oggmux ! filesink location=sine.ogg - * - * - * Record from a sound card using ALSA and encode to Ogg/Vorbis. - * - * - * gst-launch -v alsasrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg - * - * - * - * Last reviewed on 2006-03-01 (0.10.4) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include -#include - -#include -#include -#include -#include "vorbisenc.h" - -GST_DEBUG_CATEGORY_EXTERN (vorbisenc_debug); -#define GST_CAT_DEFAULT vorbisenc_debug - -static GstPadTemplate *gst_vorbis_enc_src_template, - *gst_vorbis_enc_sink_template; - -/* elementfactory information */ -static const GstElementDetails vorbisenc_details = -GST_ELEMENT_DETAILS ("Vorbis audio encoder", - "Codec/Encoder/Audio", - "Encodes audio in Vorbis format", - "Monty , " "Wim Taymans "); - -enum -{ - ARG_0, - ARG_MAX_BITRATE, - ARG_BITRATE, - ARG_MIN_BITRATE, - ARG_QUALITY, - ARG_MANAGED, - ARG_LAST_MESSAGE -}; - -static GstFlowReturn gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc); - -/* this function takes into account the granulepos_offset and the subgranule - * time offset */ -static GstClockTime -granulepos_to_timestamp_offset (GstVorbisEnc * vorbisenc, - ogg_int64_t granulepos) -{ - if (granulepos >= 0) - return gst_util_uint64_scale ((guint64) granulepos - + vorbisenc->granulepos_offset, GST_SECOND, vorbisenc->frequency) - + vorbisenc->subgranule_offset; - return GST_CLOCK_TIME_NONE; -} - -/* this function does a straight granulepos -> timestamp conversion */ -static GstClockTime -granulepos_to_timestamp (GstVorbisEnc * vorbisenc, ogg_int64_t granulepos) -{ - if (granulepos >= 0) - return gst_util_uint64_scale ((guint64) granulepos, - GST_SECOND, vorbisenc->frequency); - return GST_CLOCK_TIME_NONE; -} - -#define MAX_BITRATE_DEFAULT -1 -#define BITRATE_DEFAULT -1 -#define MIN_BITRATE_DEFAULT -1 -#define QUALITY_DEFAULT 0.3 -#define LOWEST_BITRATE 6000 /* lowest allowed for a 8 kHz stream */ -#define HIGHEST_BITRATE 250001 /* highest allowed for a 44 kHz stream */ - -static gboolean gst_vorbis_enc_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc); - -static void gst_vorbis_enc_dispose (GObject * object); -static void gst_vorbis_enc_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_vorbis_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static GstStateChangeReturn gst_vorbis_enc_change_state (GstElement * element, - GstStateChange transition); -static void gst_vorbis_enc_add_interfaces (GType vorbisenc_type); - -GST_BOILERPLATE_FULL (GstVorbisEnc, gst_vorbis_enc, GstElement, - GST_TYPE_ELEMENT, gst_vorbis_enc_add_interfaces); - -static void -gst_vorbis_enc_add_interfaces (GType vorbisenc_type) -{ - static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL }; - - g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER, - &tag_setter_info); -} - -static GstCaps * -vorbis_caps_factory (void) -{ - return gst_caps_new_simple ("audio/x-vorbis", NULL); -} - -static GstCaps * -raw_caps_factory (void) -{ - /* lowest, highest sample rates come from vorbis/lib/modes/setup_X.h: - * 1-200000 Hz */ - return - gst_caps_new_simple ("audio/x-raw-float", - "rate", GST_TYPE_INT_RANGE, 1, 200000, - "channels", GST_TYPE_INT_RANGE, 1, 256, - "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, NULL); -} - -static void -gst_vorbis_enc_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - GstCaps *raw_caps, *vorbis_caps; - - raw_caps = raw_caps_factory (); - vorbis_caps = vorbis_caps_factory (); - - gst_vorbis_enc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK, - GST_PAD_ALWAYS, raw_caps); - gst_vorbis_enc_src_template = gst_pad_template_new ("src", GST_PAD_SRC, - GST_PAD_ALWAYS, vorbis_caps); - gst_element_class_add_pad_template (element_class, - gst_vorbis_enc_sink_template); - gst_element_class_add_pad_template (element_class, - gst_vorbis_enc_src_template); - gst_element_class_set_details (element_class, &vorbisenc_details); -} - -static void -gst_vorbis_enc_class_init (GstVorbisEncClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - gobject_class->set_property = gst_vorbis_enc_set_property; - gobject_class->get_property = gst_vorbis_enc_get_property; - gobject_class->dispose = gst_vorbis_enc_dispose; - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE, - g_param_spec_int ("max-bitrate", "Maximum Bitrate", - "Specify a maximum bitrate (in bps). Useful for streaming " - "applications. (-1 == disabled)", - -1, HIGHEST_BITRATE, MAX_BITRATE_DEFAULT, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE, - g_param_spec_int ("bitrate", "Target Bitrate", - "Attempt to encode at a bitrate averaging this (in bps). " - "This uses the bitrate management engine, and is not recommended for most users. " - "Quality is a better alternative. (-1 == disabled)", - -1, HIGHEST_BITRATE, BITRATE_DEFAULT, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MIN_BITRATE, - g_param_spec_int ("min_bitrate", "Minimum Bitrate", - "Specify a minimum bitrate (in bps). Useful for encoding for a " - "fixed-size channel. (-1 == disabled)", - -1, HIGHEST_BITRATE, MIN_BITRATE_DEFAULT, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY, - g_param_spec_float ("quality", "Quality", - "Specify quality instead of specifying a particular bitrate.", - -0.1, 1.0, QUALITY_DEFAULT, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED, - g_param_spec_boolean ("managed", "Managed", - "Enable bitrate management engine", FALSE, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE, - g_param_spec_string ("last-message", "last-message", - "The last status message", NULL, G_PARAM_READABLE)); - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_vorbis_enc_change_state); -} - -static void -gst_vorbis_enc_dispose (GObject * object) -{ - GstVorbisEnc *vorbisenc = GST_VORBISENC (object); - - if (vorbisenc->sinkcaps) { - gst_caps_unref (vorbisenc->sinkcaps); - vorbisenc->sinkcaps = NULL; - } - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static const GstAudioChannelPosition vorbischannelpositions[][6] = { - { /* Mono */ - GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}, - { /* Stereo */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, - { /* Stereo + Centre */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, - { /* Quadraphonic */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - }, - { /* Stereo + Centre + rear stereo */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - }, - { /* Full 5.1 Surround */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_LFE, - }, -}; -static GstCaps * -gst_vorbis_enc_generate_sink_caps (void) -{ - GstCaps *caps = gst_caps_new_empty (); - int i, c; - - gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float", - "rate", GST_TYPE_INT_RANGE, 1, 200000, - "channels", G_TYPE_INT, 1, - "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, - NULL)); - - gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float", - "rate", GST_TYPE_INT_RANGE, 1, 200000, - "channels", G_TYPE_INT, 2, - "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, - NULL)); - - for (i = 3; i <= 6; i++) { - GValue chanpos = { 0 }; - GValue pos = { 0 }; - GstStructure *structure; - - g_value_init (&chanpos, GST_TYPE_ARRAY); - g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION); - - for (c = 0; c < i; c++) { - g_value_set_enum (&pos, vorbischannelpositions[i - 1][c]); - gst_value_array_append_value (&chanpos, &pos); - } - g_value_unset (&pos); - - structure = gst_structure_new ("audio/x-raw-float", - "rate", GST_TYPE_INT_RANGE, 1, 200000, - "channels", G_TYPE_INT, i, - "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, NULL); - gst_structure_set_value (structure, "channel-positions", &chanpos); - g_value_unset (&chanpos); - - gst_caps_append_structure (caps, structure); - } - - gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float", - "rate", GST_TYPE_INT_RANGE, 1, 200000, - "channels", GST_TYPE_INT_RANGE, 7, 256, - "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, - NULL)); - - return caps; -} - -static GstCaps * -gst_vorbis_enc_sink_getcaps (GstPad * pad) -{ - GstVorbisEnc *vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); - - if (vorbisenc->sinkcaps == NULL) - vorbisenc->sinkcaps = gst_vorbis_enc_generate_sink_caps (); - - return gst_caps_ref (vorbisenc->sinkcaps); -} - -static gboolean -gst_vorbis_enc_sink_setcaps (GstPad * pad, GstCaps * caps) -{ - GstVorbisEnc *vorbisenc; - GstStructure *structure; - - vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); - vorbisenc->setup = FALSE; - - structure = gst_caps_get_structure (caps, 0); - gst_structure_get_int (structure, "channels", &vorbisenc->channels); - gst_structure_get_int (structure, "rate", &vorbisenc->frequency); - - gst_vorbis_enc_setup (vorbisenc); - - if (vorbisenc->setup) - return TRUE; - - return FALSE; -} - -static gboolean -gst_vorbis_enc_convert_src (GstPad * pad, GstFormat src_format, - gint64 src_value, GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = TRUE; - GstVorbisEnc *vorbisenc; - gint64 avg; - - vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad)); - - if (vorbisenc->samples_in == 0 || - vorbisenc->bytes_out == 0 || vorbisenc->frequency == 0) { - gst_object_unref (vorbisenc); - return FALSE; - } - - avg = (vorbisenc->bytes_out * vorbisenc->frequency) / (vorbisenc->samples_in); - - switch (src_format) { - case GST_FORMAT_BYTES: - switch (*dest_format) { - case GST_FORMAT_TIME: - *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND, avg); - break; - default: - res = FALSE; - } - break; - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_BYTES: - *dest_value = gst_util_uint64_scale_int (src_value, avg, GST_SECOND); - break; - default: - res = FALSE; - } - break; - default: - res = FALSE; - } - gst_object_unref (vorbisenc); - return res; -} - -static gboolean -gst_vorbis_enc_convert_sink (GstPad * pad, GstFormat src_format, - gint64 src_value, GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = TRUE; - guint scale = 1; - gint bytes_per_sample; - GstVorbisEnc *vorbisenc; - - vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad)); - - bytes_per_sample = vorbisenc->channels * 2; - - switch (src_format) { - case GST_FORMAT_BYTES: - switch (*dest_format) { - case GST_FORMAT_DEFAULT: - if (bytes_per_sample == 0) - return FALSE; - *dest_value = src_value / bytes_per_sample; - break; - case GST_FORMAT_TIME: - { - gint byterate = bytes_per_sample * vorbisenc->frequency; - - if (byterate == 0) - return FALSE; - *dest_value = - gst_util_uint64_scale_int (src_value, GST_SECOND, byterate); - break; - } - default: - res = FALSE; - } - break; - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_BYTES: - *dest_value = src_value * bytes_per_sample; - break; - case GST_FORMAT_TIME: - if (vorbisenc->frequency == 0) - return FALSE; - *dest_value = - gst_util_uint64_scale_int (src_value, GST_SECOND, - vorbisenc->frequency); - break; - default: - res = FALSE; - } - break; - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_BYTES: - scale = bytes_per_sample; - /* fallthrough */ - case GST_FORMAT_DEFAULT: - *dest_value = - gst_util_uint64_scale_int (src_value, - scale * vorbisenc->frequency, GST_SECOND); - break; - default: - res = FALSE; - } - break; - default: - res = FALSE; - } - gst_object_unref (vorbisenc); - return res; -} - -static const GstQueryType * -gst_vorbis_enc_get_query_types (GstPad * pad) -{ - static const GstQueryType gst_vorbis_enc_src_query_types[] = { - GST_QUERY_POSITION, - GST_QUERY_DURATION, - GST_QUERY_CONVERT, - 0 - }; - - return gst_vorbis_enc_src_query_types; -} - -static gboolean -gst_vorbis_enc_src_query (GstPad * pad, GstQuery * query) -{ - gboolean res = TRUE; - GstVorbisEnc *vorbisenc; - GstPad *peerpad; - - vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad)); - peerpad = gst_pad_get_peer (GST_PAD (vorbisenc->sinkpad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - { - GstFormat fmt, req_fmt; - gint64 pos, val; - - gst_query_parse_position (query, &req_fmt, NULL); - if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) { - gst_query_set_position (query, req_fmt, val); - break; - } - - fmt = GST_FORMAT_TIME; - if (!(res = gst_pad_query_position (peerpad, &fmt, &pos))) - break; - - if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val))) { - gst_query_set_position (query, req_fmt, val); - } - break; - } - case GST_QUERY_DURATION: - { - GstFormat fmt, req_fmt; - gint64 dur, val; - - gst_query_parse_duration (query, &req_fmt, NULL); - if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) { - gst_query_set_duration (query, req_fmt, val); - break; - } - - fmt = GST_FORMAT_TIME; - if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur))) - break; - - if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) { - gst_query_set_duration (query, req_fmt, val); - } - break; - } - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - if (!(res = - gst_vorbis_enc_convert_src (pad, src_fmt, src_val, &dest_fmt, - &dest_val))) - goto error; - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - -error: - gst_object_unref (peerpad); - gst_object_unref (vorbisenc); - return res; -} - -static gboolean -gst_vorbis_enc_sink_query (GstPad * pad, GstQuery * query) -{ - gboolean res = TRUE; - GstVorbisEnc *vorbisenc; - - vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - if (!(res = - gst_vorbis_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt, - &dest_val))) - goto error; - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - -error: - return res; -} - -static void -gst_vorbis_enc_init (GstVorbisEnc * vorbisenc, GstVorbisEncClass * klass) -{ - vorbisenc->sinkpad = - gst_pad_new_from_template (gst_vorbis_enc_sink_template, "sink"); - gst_pad_set_event_function (vorbisenc->sinkpad, - GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_event)); - gst_pad_set_chain_function (vorbisenc->sinkpad, - GST_DEBUG_FUNCPTR (gst_vorbis_enc_chain)); - gst_pad_set_setcaps_function (vorbisenc->sinkpad, - GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_setcaps)); - gst_pad_set_getcaps_function (vorbisenc->sinkpad, - GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_getcaps)); - gst_pad_set_query_function (vorbisenc->sinkpad, - GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_query)); - gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->sinkpad); - - vorbisenc->srcpad = - gst_pad_new_from_template (gst_vorbis_enc_src_template, "src"); - gst_pad_set_query_function (vorbisenc->srcpad, - GST_DEBUG_FUNCPTR (gst_vorbis_enc_src_query)); - gst_pad_set_query_type_function (vorbisenc->srcpad, - GST_DEBUG_FUNCPTR (gst_vorbis_enc_get_query_types)); - gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->srcpad); - - vorbisenc->channels = -1; - vorbisenc->frequency = -1; - - vorbisenc->managed = FALSE; - vorbisenc->max_bitrate = MAX_BITRATE_DEFAULT; - vorbisenc->bitrate = BITRATE_DEFAULT; - vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT; - vorbisenc->quality = QUALITY_DEFAULT; - vorbisenc->quality_set = FALSE; - vorbisenc->last_message = NULL; -} - -static void -gst_vorbis_enc_metadata_set1 (const GstTagList * list, const gchar * tag, - gpointer vorbisenc) -{ - GstVorbisEnc *enc = GST_VORBISENC (vorbisenc); - GList *vc_list, *l; - - vc_list = gst_tag_to_vorbis_comments (list, tag); - - for (l = vc_list; l != NULL; l = l->next) { - const gchar *vc_string = (const gchar *) l->data; - gchar *key = NULL, *val = NULL; - - GST_LOG_OBJECT (vorbisenc, "vorbis comment: %s", vc_string); - if (gst_tag_parse_extended_comment (vc_string, &key, NULL, &val, TRUE)) { - vorbis_comment_add_tag (&enc->vc, key, val); - g_free (key); - g_free (val); - } - } - - g_list_foreach (vc_list, (GFunc) g_free, NULL); - g_list_free (vc_list); -} - -static void -gst_vorbis_enc_set_metadata (GstVorbisEnc * enc) -{ - GstTagList *merged_tags; - const GstTagList *user_tags; - - vorbis_comment_init (&enc->vc); - - user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc)); - - GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags); - GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags); - - /* gst_tag_list_merge() will handle NULL for either or both lists fine */ - merged_tags = gst_tag_list_merge (user_tags, enc->tags, - gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc))); - - if (merged_tags) { - GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags); - gst_tag_list_foreach (merged_tags, gst_vorbis_enc_metadata_set1, enc); - gst_tag_list_free (merged_tags); - } -} - -static gchar * -get_constraints_string (GstVorbisEnc * vorbisenc) -{ - gint min = vorbisenc->min_bitrate; - gint max = vorbisenc->max_bitrate; - gchar *result; - - if (min > 0 && max > 0) - result = g_strdup_printf ("(min %d bps, max %d bps)", min, max); - else if (min > 0) - result = g_strdup_printf ("(min %d bps, no max)", min); - else if (max > 0) - result = g_strdup_printf ("(no min, max %d bps)", max); - else - result = g_strdup_printf ("(no min or max)"); - - return result; -} - -static void -update_start_message (GstVorbisEnc * vorbisenc) -{ - gchar *constraints; - - g_free (vorbisenc->last_message); - - if (vorbisenc->bitrate > 0) { - if (vorbisenc->managed) { - constraints = get_constraints_string (vorbisenc); - vorbisenc->last_message = - g_strdup_printf ("encoding at average bitrate %d bps %s", - vorbisenc->bitrate, constraints); - g_free (constraints); - } else { - vorbisenc->last_message = - g_strdup_printf - ("encoding at approximate bitrate %d bps (VBR encoding enabled)", - vorbisenc->bitrate); - } - } else { - if (vorbisenc->quality_set) { - if (vorbisenc->managed) { - constraints = get_constraints_string (vorbisenc); - vorbisenc->last_message = - g_strdup_printf - ("encoding at quality level %2.2f using constrained VBR %s", - vorbisenc->quality, constraints); - g_free (constraints); - } else { - vorbisenc->last_message = - g_strdup_printf ("encoding at quality level %2.2f", - vorbisenc->quality); - } - } else { - constraints = get_constraints_string (vorbisenc); - vorbisenc->last_message = - g_strdup_printf ("encoding using bitrate management %s", constraints); - g_free (constraints); - } - } - - g_object_notify (G_OBJECT (vorbisenc), "last_message"); -} - -static gboolean -gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc) -{ - vorbisenc->setup = FALSE; - - if (vorbisenc->bitrate < 0 && vorbisenc->min_bitrate < 0 - && vorbisenc->max_bitrate < 0) { - vorbisenc->quality_set = TRUE; - } - - update_start_message (vorbisenc); - - /* choose an encoding mode */ - /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */ - vorbis_info_init (&vorbisenc->vi); - - if (vorbisenc->quality_set) { - if (vorbis_encode_setup_vbr (&vorbisenc->vi, - vorbisenc->channels, vorbisenc->frequency, - vorbisenc->quality) != 0) { - GST_ERROR_OBJECT (vorbisenc, - "vorbisenc: initialisation failed: invalid parameters for quality"); - vorbis_info_clear (&vorbisenc->vi); - return FALSE; - } - - /* do we have optional hard quality restrictions? */ - if (vorbisenc->max_bitrate > 0 || vorbisenc->min_bitrate > 0) { - struct ovectl_ratemanage_arg ai; - - vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_GET, &ai); - - ai.bitrate_hard_min = vorbisenc->min_bitrate; - ai.bitrate_hard_max = vorbisenc->max_bitrate; - ai.management_active = 1; - - vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, &ai); - } - } else { - long min_bitrate, max_bitrate; - - min_bitrate = vorbisenc->min_bitrate > 0 ? vorbisenc->min_bitrate : -1; - max_bitrate = vorbisenc->max_bitrate > 0 ? vorbisenc->max_bitrate : -1; - - if (vorbis_encode_setup_managed (&vorbisenc->vi, - vorbisenc->channels, - vorbisenc->frequency, - max_bitrate, vorbisenc->bitrate, min_bitrate) != 0) { - GST_ERROR_OBJECT (vorbisenc, - "vorbis_encode_setup_managed " - "(c %d, rate %d, max br %ld, br %d, min br %ld) failed", - vorbisenc->channels, vorbisenc->frequency, max_bitrate, - vorbisenc->bitrate, min_bitrate); - vorbis_info_clear (&vorbisenc->vi); - return FALSE; - } - } - - if (vorbisenc->managed && vorbisenc->bitrate < 0) { - vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_AVG, NULL); - } else if (!vorbisenc->managed) { - /* Turn off management entirely (if it was turned on). */ - vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, NULL); - } - vorbis_encode_setup_init (&vorbisenc->vi); - - /* set up the analysis state and auxiliary encoding storage */ - vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi); - vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb); - - vorbisenc->next_ts = 0; - - vorbisenc->setup = TRUE; - - return TRUE; -} - -static GstFlowReturn -gst_vorbis_enc_clear (GstVorbisEnc * vorbisenc) -{ - GstFlowReturn ret = GST_FLOW_OK; - - if (vorbisenc->setup) { - vorbis_analysis_wrote (&vorbisenc->vd, 0); - ret = gst_vorbis_enc_output_buffers (vorbisenc); - - vorbisenc->setup = FALSE; - } - - /* clean up and exit. vorbis_info_clear() must be called last */ - vorbis_block_clear (&vorbisenc->vb); - vorbis_dsp_clear (&vorbisenc->vd); - vorbis_info_clear (&vorbisenc->vi); - - vorbisenc->header_sent = FALSE; - - return ret; -} - -/* prepare a buffer for transmission by passing data through libvorbis */ -static GstBuffer * -gst_vorbis_enc_buffer_from_packet (GstVorbisEnc * vorbisenc, - ogg_packet * packet) -{ - GstBuffer *outbuf; - - outbuf = gst_buffer_new_and_alloc (packet->bytes); - memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes); - /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its - * time representation */ - GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos + - vorbisenc->granulepos_offset; - GST_BUFFER_OFFSET (outbuf) = granulepos_to_timestamp (vorbisenc, - GST_BUFFER_OFFSET_END (outbuf)); - GST_BUFFER_TIMESTAMP (outbuf) = vorbisenc->next_ts; - - /* update the next timestamp, taking granulepos_offset and subgranule offset - * into account */ - vorbisenc->next_ts = - granulepos_to_timestamp_offset (vorbisenc, packet->granulepos); - GST_BUFFER_DURATION (outbuf) = - vorbisenc->next_ts - GST_BUFFER_TIMESTAMP (outbuf); - - if (vorbisenc->next_discont) { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - vorbisenc->next_discont = FALSE; - } - - GST_LOG_OBJECT (vorbisenc, "encoded buffer of %d bytes", - GST_BUFFER_SIZE (outbuf)); - return outbuf; -} - -/* the same as above, but different logic for setting timestamp and granulepos - * */ -static GstBuffer * -gst_vorbis_enc_buffer_from_header_packet (GstVorbisEnc * vorbisenc, - ogg_packet * packet) -{ - GstBuffer *outbuf; - - outbuf = gst_buffer_new_and_alloc (packet->bytes); - memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes); - GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out; - GST_BUFFER_OFFSET_END (outbuf) = 0; - GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; - GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; - - gst_buffer_set_caps (outbuf, vorbisenc->srccaps); - - GST_DEBUG ("created header packet buffer, %d bytes", - GST_BUFFER_SIZE (outbuf)); - return outbuf; -} - -/* push out the buffer and do internal bookkeeping */ -static GstFlowReturn -gst_vorbis_enc_push_buffer (GstVorbisEnc * vorbisenc, GstBuffer * buffer) -{ - vorbisenc->bytes_out += GST_BUFFER_SIZE (buffer); - - GST_DEBUG_OBJECT (vorbisenc, "Pushing buffer with GP %lld, ts %lld", - GST_BUFFER_OFFSET_END (buffer), GST_BUFFER_TIMESTAMP (buffer)); - return gst_pad_push (vorbisenc->srcpad, buffer); -} - -static GstFlowReturn -gst_vorbis_enc_push_packet (GstVorbisEnc * vorbisenc, ogg_packet * packet) -{ - GstBuffer *outbuf; - - outbuf = gst_vorbis_enc_buffer_from_packet (vorbisenc, packet); - return gst_vorbis_enc_push_buffer (vorbisenc, outbuf); -} - -/* Set a copy of these buffers as 'streamheader' on the caps. - * We need a copy to avoid these buffers ending up with (indirect) refs on - * themselves - */ -static GstCaps * -gst_vorbis_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1, - GstBuffer * buf2, GstBuffer * buf3) -{ - GstBuffer *buf; - GstStructure *structure; - GValue array = { 0 }; - GValue value = { 0 }; - - caps = gst_caps_make_writable (caps); - structure = gst_caps_get_structure (caps, 0); - - /* mark buffers */ - GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS); - GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS); - GST_BUFFER_FLAG_SET (buf3, GST_BUFFER_FLAG_IN_CAPS); - - /* put buffers in a fixed list */ - g_value_init (&array, GST_TYPE_ARRAY); - g_value_init (&value, GST_TYPE_BUFFER); - buf = gst_buffer_copy (buf1); - gst_value_set_buffer (&value, buf); - gst_buffer_unref (buf); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - g_value_init (&value, GST_TYPE_BUFFER); - buf = gst_buffer_copy (buf2); - gst_value_set_buffer (&value, buf); - gst_buffer_unref (buf); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - g_value_init (&value, GST_TYPE_BUFFER); - buf = gst_buffer_copy (buf3); - gst_value_set_buffer (&value, buf); - gst_buffer_unref (buf); - gst_value_array_append_value (&array, &value); - gst_structure_set_value (structure, "streamheader", &array); - g_value_unset (&value); - g_value_unset (&array); - - return caps; -} - -static gboolean -gst_vorbis_enc_sink_event (GstPad * pad, GstEvent * event) -{ - gboolean res = TRUE; - GstVorbisEnc *vorbisenc; - - vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - /* Tell the library we're at end of stream so that it can handle - * the last frame and mark end of stream in the output properly */ - GST_DEBUG_OBJECT (vorbisenc, "EOS, clearing state and sending event on"); - gst_vorbis_enc_clear (vorbisenc); - - res = gst_pad_push_event (vorbisenc->srcpad, event); - break; - case GST_EVENT_TAG: - if (vorbisenc->tags) { - GstTagList *list; - - gst_event_parse_tag (event, &list); - gst_tag_list_insert (vorbisenc->tags, list, - gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc))); - } else { - g_assert_not_reached (); - } - res = gst_pad_push_event (vorbisenc->srcpad, event); - break; - default: - res = gst_pad_push_event (vorbisenc->srcpad, event); - break; - } - return res; -} - -static gboolean -gst_vorbis_enc_buffer_check_discontinuous (GstVorbisEnc * vorbisenc, - GstBuffer * buffer) -{ - gboolean ret = FALSE; - - if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE && - vorbisenc->expected_ts != GST_CLOCK_TIME_NONE && - GST_BUFFER_TIMESTAMP (buffer) != vorbisenc->expected_ts) { - /* It turns out that a lot of elements don't generate perfect streams due - * to rounding errors. So, we permit small errors (< 1/2 a sample) without - * causing a discont. - */ - int halfsample = GST_SECOND / vorbisenc->frequency / 2; - - if ((GstClockTimeDiff) (GST_BUFFER_TIMESTAMP (buffer) - - vorbisenc->expected_ts) > halfsample) { - GST_DEBUG_OBJECT (vorbisenc, "Expected TS %" GST_TIME_FORMAT - ", buffer TS %" GST_TIME_FORMAT, - GST_TIME_ARGS (vorbisenc->expected_ts), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); - ret = TRUE; - } - } - - if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE && - GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE) { - vorbisenc->expected_ts = GST_BUFFER_TIMESTAMP (buffer) + - GST_BUFFER_DURATION (buffer); - } else - vorbisenc->expected_ts = GST_CLOCK_TIME_NONE; - - return ret; -} - -static GstFlowReturn -gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer) -{ - GstVorbisEnc *vorbisenc; - GstFlowReturn ret = GST_FLOW_OK; - gfloat *data; - gulong size; - gulong i, j; - float **vorbis_buffer; - GstBuffer *buf1, *buf2, *buf3; - gboolean first = FALSE; - - vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); - - if (!vorbisenc->setup) - goto not_setup; - - if (!vorbisenc->header_sent) { - /* Vorbis streams begin with three headers; the initial header (with - most of the codec setup parameters) which is mandated by the Ogg - bitstream spec. The second header holds any comment fields. The - third header holds the bitstream codebook. We merely need to - make the headers, then pass them to libvorbis one at a time; - libvorbis handles the additional Ogg bitstream constraints */ - ogg_packet header; - ogg_packet header_comm; - ogg_packet header_code; - GstCaps *caps; - - /* first, make sure header buffers get timestamp == 0 */ - vorbisenc->next_ts = 0; - vorbisenc->granulepos_offset = 0; - vorbisenc->subgranule_offset = 0; - - GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets"); - gst_vorbis_enc_set_metadata (vorbisenc); - vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header, - &header_comm, &header_code); - vorbis_comment_clear (&vorbisenc->vc); - - /* create header buffers */ - buf1 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header); - buf2 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_comm); - buf3 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_code); - - /* mark and put on caps */ - vorbisenc->srccaps = gst_caps_new_simple ("audio/x-vorbis", NULL); - caps = vorbisenc->srccaps; - caps = gst_vorbis_enc_set_header_on_caps (caps, buf1, buf2, buf3); - - /* negotiate with these caps */ - GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps); - gst_pad_set_caps (vorbisenc->srcpad, caps); - - gst_buffer_set_caps (buf1, caps); - gst_buffer_set_caps (buf2, caps); - gst_buffer_set_caps (buf3, caps); - - /* push out buffers */ - /* push_buffer takes the reference even for failure */ - if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf1)) != GST_FLOW_OK) - goto failed_header_push; - if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf2)) != GST_FLOW_OK) { - buf2 = NULL; - goto failed_header_push; - } - if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf3)) != GST_FLOW_OK) { - buf3 = NULL; - goto failed_header_push; - } - - /* now adjust starting granulepos accordingly if the buffer's timestamp is - nonzero */ - vorbisenc->next_ts = GST_BUFFER_TIMESTAMP (buffer); - vorbisenc->expected_ts = GST_BUFFER_TIMESTAMP (buffer); - vorbisenc->granulepos_offset = gst_util_uint64_scale - (GST_BUFFER_TIMESTAMP (buffer), vorbisenc->frequency, GST_SECOND); - vorbisenc->subgranule_offset = 0; - vorbisenc->subgranule_offset = - vorbisenc->next_ts - granulepos_to_timestamp_offset (vorbisenc, 0); - - vorbisenc->header_sent = TRUE; - first = TRUE; - } - - if (vorbisenc->expected_ts != GST_CLOCK_TIME_NONE && - GST_BUFFER_TIMESTAMP (buffer) < vorbisenc->expected_ts) { - GST_WARNING_OBJECT (vorbisenc, "Buffer is older than previous " - "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT - "), cannot handle. Dropping buffer.", - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), - GST_TIME_ARGS (vorbisenc->expected_ts)); - gst_buffer_unref (buffer); - return GST_FLOW_OK; - } - - if (gst_vorbis_enc_buffer_check_discontinuous (vorbisenc, buffer) && !first) { - GST_WARNING_OBJECT (vorbisenc, "Buffer is discontinuous, flushing encoder " - "and restarting (Discont from %" GST_TIME_FORMAT - " to %" GST_TIME_FORMAT ")", GST_TIME_ARGS (vorbisenc->next_ts), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); - /* Re-initialise encoder (there's unfortunately no API to flush it) */ - if ((ret = gst_vorbis_enc_clear (vorbisenc)) != GST_FLOW_OK) - return ret; - if (!gst_vorbis_enc_setup (vorbisenc)) - return GST_FLOW_ERROR; /* Should be impossible, we can only get here if - we successfully initialised earlier */ - - /* Now, set our granulepos offset appropriately. */ - vorbisenc->next_ts = GST_BUFFER_TIMESTAMP (buffer); - /* We need to round to the nearest whole number of samples, not just do - * a truncating division here */ - vorbisenc->granulepos_offset = gst_util_uint64_scale - (GST_BUFFER_TIMESTAMP (buffer) + GST_SECOND / vorbisenc->frequency / 2 - - vorbisenc->subgranule_offset, vorbisenc->frequency, GST_SECOND); - - vorbisenc->header_sent = TRUE; - - /* And our next output buffer must have DISCONT set on it */ - vorbisenc->next_discont = TRUE; - } - - /* Sending zero samples to libvorbis marks EOS, so we mustn't do that */ - if (GST_BUFFER_SIZE (buffer) == 0) { - gst_buffer_unref (buffer); - return GST_FLOW_OK; - } - - /* data to encode */ - data = (gfloat *) GST_BUFFER_DATA (buffer); - size = GST_BUFFER_SIZE (buffer) / (vorbisenc->channels * sizeof (float)); - - /* expose the buffer to submit data */ - vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size); - - /* deinterleave samples, write the buffer data */ - for (i = 0; i < size; i++) { - for (j = 0; j < vorbisenc->channels; j++) { - vorbis_buffer[j][i] = *data++; - } - } - - /* tell the library how much we actually submitted */ - vorbis_analysis_wrote (&vorbisenc->vd, size); - - vorbisenc->samples_in += size; - - gst_buffer_unref (buffer); - - ret = gst_vorbis_enc_output_buffers (vorbisenc); - - return ret; - - /* error cases */ -not_setup: - { - gst_buffer_unref (buffer); - GST_ELEMENT_ERROR (vorbisenc, CORE, NEGOTIATION, (NULL), - ("encoder not initialized (input is not audio?)")); - return GST_FLOW_UNEXPECTED; - } -failed_header_push: - { - GST_WARNING_OBJECT (vorbisenc, "Failed to push headers"); - /* buf1 is always already unreffed */ - if (buf2) - gst_buffer_unref (buf2); - if (buf3) - gst_buffer_unref (buf3); - gst_buffer_unref (buffer); - return ret; - } -} - -static GstFlowReturn -gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc) -{ - GstFlowReturn ret; - - /* vorbis does some data preanalysis, then divides up blocks for - more involved (potentially parallel) processing. Get a single - block for encoding now */ - while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) { - ogg_packet op; - - GST_LOG_OBJECT (vorbisenc, "analysed to a block"); - - /* analysis */ - vorbis_analysis (&vorbisenc->vb, NULL); - vorbis_bitrate_addblock (&vorbisenc->vb); - - while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) { - GST_LOG_OBJECT (vorbisenc, "pushing out a data packet"); - ret = gst_vorbis_enc_push_packet (vorbisenc, &op); - - if (ret != GST_FLOW_OK) - return ret; - } - } - - return GST_FLOW_OK; -} - -static void -gst_vorbis_enc_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstVorbisEnc *vorbisenc; - - g_return_if_fail (GST_IS_VORBISENC (object)); - - vorbisenc = GST_VORBISENC (object); - - switch (prop_id) { - case ARG_MAX_BITRATE: - g_value_set_int (value, vorbisenc->max_bitrate); - break; - case ARG_BITRATE: - g_value_set_int (value, vorbisenc->bitrate); - break; - case ARG_MIN_BITRATE: - g_value_set_int (value, vorbisenc->min_bitrate); - break; - case ARG_QUALITY: - g_value_set_float (value, vorbisenc->quality); - break; - case ARG_MANAGED: - g_value_set_boolean (value, vorbisenc->managed); - break; - case ARG_LAST_MESSAGE: - g_value_set_string (value, vorbisenc->last_message); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_vorbis_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstVorbisEnc *vorbisenc; - - g_return_if_fail (GST_IS_VORBISENC (object)); - - vorbisenc = GST_VORBISENC (object); - - switch (prop_id) { - case ARG_MAX_BITRATE: - { - gboolean old_value = vorbisenc->managed; - - vorbisenc->max_bitrate = g_value_get_int (value); - if (vorbisenc->max_bitrate >= 0 - && vorbisenc->max_bitrate < LOWEST_BITRATE) { - g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE); - vorbisenc->max_bitrate = LOWEST_BITRATE; - } - if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0) - vorbisenc->managed = TRUE; - else - vorbisenc->managed = FALSE; - - if (old_value != vorbisenc->managed) - g_object_notify (object, "managed"); - break; - } - case ARG_BITRATE: - vorbisenc->bitrate = g_value_get_int (value); - if (vorbisenc->bitrate >= 0 && vorbisenc->bitrate < LOWEST_BITRATE) { - g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE); - vorbisenc->bitrate = LOWEST_BITRATE; - } - break; - case ARG_MIN_BITRATE: - { - gboolean old_value = vorbisenc->managed; - - vorbisenc->min_bitrate = g_value_get_int (value); - if (vorbisenc->min_bitrate >= 0 - && vorbisenc->min_bitrate < LOWEST_BITRATE) { - g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE); - vorbisenc->min_bitrate = LOWEST_BITRATE; - } - if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0) - vorbisenc->managed = TRUE; - else - vorbisenc->managed = FALSE; - - if (old_value != vorbisenc->managed) - g_object_notify (object, "managed"); - break; - } - case ARG_QUALITY: - vorbisenc->quality = g_value_get_float (value); - if (vorbisenc->quality >= 0.0) - vorbisenc->quality_set = TRUE; - else - vorbisenc->quality_set = FALSE; - break; - case ARG_MANAGED: - vorbisenc->managed = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_vorbis_enc_change_state (GstElement * element, GstStateChange transition) -{ - GstVorbisEnc *vorbisenc = GST_VORBISENC (element); - GstStateChangeReturn res; - - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - vorbisenc->tags = gst_tag_list_new (); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - vorbisenc->setup = FALSE; - vorbisenc->next_discont = FALSE; - vorbisenc->header_sent = FALSE; - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - vorbis_block_clear (&vorbisenc->vb); - vorbis_dsp_clear (&vorbisenc->vd); - vorbis_info_clear (&vorbisenc->vi); - g_free (vorbisenc->last_message); - vorbisenc->last_message = NULL; - if (vorbisenc->srccaps) { - gst_caps_unref (vorbisenc->srccaps); - vorbisenc->srccaps = NULL; - } - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_tag_list_free (vorbisenc->tags); - vorbisenc->tags = NULL; - default: - break; - } - - return res; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/vorbis/vorbisenc.h --- a/gst_plugins_base/ext/vorbis/vorbisenc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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. - */ - - -#ifndef __GST_VORBIS_ENC_H__ -#define __GST_VORBIS_ENC_H__ - - -#include - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_VORBISENC \ - (gst_vorbis_enc_get_type()) -#define GST_VORBISENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VORBISENC,GstVorbisEnc)) -#define GST_VORBISENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VORBISENC,GstVorbisEncClass)) -#define GST_IS_VORBISENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBISENC)) -#define GST_IS_VORBISENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBISENC)) - -typedef struct _GstVorbisEnc GstVorbisEnc; -typedef struct _GstVorbisEncClass GstVorbisEncClass; - -/** - * GstVorbisEnc: - * - * Opaque data structure. - */ -struct _GstVorbisEnc { - GstElement element; - - GstPad *sinkpad; - GstPad *srcpad; - - GstCaps *srccaps; - GstCaps *sinkcaps; - - vorbis_info vi; /* struct that stores all the static vorbis bitstream - settings */ - vorbis_comment vc; /* struct that stores all the user comments */ - - vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ - vorbis_block vb; /* local working space for packet->PCM decode */ - - gboolean managed; - gint bitrate; - gint min_bitrate; - gint max_bitrate; - gfloat quality; - gboolean quality_set; - - gint channels; - gint frequency; - - guint64 samples_in; - guint64 bytes_out; - GstClockTime next_ts; - GstClockTime expected_ts; - gboolean next_discont; - guint64 granulepos_offset; - gint64 subgranule_offset; - - GstTagList * tags; - - gboolean setup; - gboolean header_sent; - gchar *last_message; -}; - -struct _GstVorbisEncClass { - GstElementClass parent_class; -}; - -GType gst_vorbis_enc_get_type(void); - -G_END_DECLS - -#endif /* __GST_VORBIS_ENC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/vorbis/vorbisparse.c --- a/gst_plugins_base/ext/vorbis/vorbisparse.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,666 +0,0 @@ -/* GStreamer - * Copyright (C) <2004> Thomas Vander Stichele - * Copyright (C) 2006 Andy Wingo - * - * 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. - */ - -/** - * SECTION:element-vorbisparse - * @short_description: parses vorbis streams - * @see_also: vorbisdec, oggdemux, theoraparse - * - * - * - * The vorbisparse element will parse the header packets of the Vorbis - * stream and put them as the streamheader in the caps. This is used in the - * multifdsink case where you want to stream live vorbis streams to multiple - * clients, each client has to receive the streamheaders first before they can - * consume the vorbis packets. - * - * - * This element also makes sure that the buffers that it pushes out are properly - * timestamped and that their offset and offset_end are set. The buffers that - * vorbisparse outputs have all of the metadata that oggmux expects to receive, - * which allows you to (for example) remux an ogg/vorbis file. - * - * Example pipelines - * - * - * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisparse ! fakesink - * - * This pipeline shows that the streamheader is set in the caps, and that each - * buffer has the timestamp, duration, offset, and offset_end set. - * - * - * - * gst-launch filesrc location=sine.ogg ! oggdemux ! vorbisparse \ - * ! oggmux ! filesink location=sine-remuxed.ogg - * - * This pipeline shows remuxing. sine-remuxed.ogg might not be exactly the same - * as sine.ogg, but they should produce exactly the same decoded data. - * - * - * - * Last reviewed on 2006-04-01 (0.10.4.1) - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "vorbisparse.h" - -GST_DEBUG_CATEGORY_EXTERN (vorbisparse_debug); -#define GST_CAT_DEFAULT vorbisparse_debug - -static const GstElementDetails vorbis_parse_details = { - "VorbisParse", - "Codec/Parser/Audio", - "parse raw vorbis streams", - "Thomas Vander Stichele " -}; - -static GstStaticPadTemplate vorbis_parse_sink_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-vorbis") - ); - -static GstStaticPadTemplate vorbis_parse_src_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-vorbis") - ); - -GST_BOILERPLATE (GstVorbisParse, gst_vorbis_parse, GstElement, - GST_TYPE_ELEMENT); - -static GstFlowReturn vorbis_parse_chain (GstPad * pad, GstBuffer * buffer); -static GstStateChangeReturn vorbis_parse_change_state (GstElement * element, - GstStateChange transition); -static gboolean vorbis_parse_sink_event (GstPad * pad, GstEvent * event); -static gboolean vorbis_parse_src_query (GstPad * pad, GstQuery * query); -static gboolean vorbis_parse_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value); -static GstFlowReturn vorbis_parse_parse_packet (GstVorbisParse * parse, - GstBuffer * buf); - -static void -gst_vorbis_parse_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&vorbis_parse_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&vorbis_parse_sink_factory)); - gst_element_class_set_details (element_class, &vorbis_parse_details); -} - -static void -gst_vorbis_parse_class_init (GstVorbisParseClass * klass) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - - gstelement_class->change_state = vorbis_parse_change_state; - - klass->parse_packet = GST_DEBUG_FUNCPTR (vorbis_parse_parse_packet); -} - -static void -gst_vorbis_parse_init (GstVorbisParse * parse, GstVorbisParseClass * g_class) -{ - parse->sinkpad = - gst_pad_new_from_static_template (&vorbis_parse_sink_factory, "sink"); - gst_pad_set_chain_function (parse->sinkpad, - GST_DEBUG_FUNCPTR (vorbis_parse_chain)); - gst_pad_set_event_function (parse->sinkpad, - GST_DEBUG_FUNCPTR (vorbis_parse_sink_event)); - gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad); - - parse->srcpad = - gst_pad_new_from_static_template (&vorbis_parse_src_factory, "src"); - gst_pad_set_query_function (parse->srcpad, - GST_DEBUG_FUNCPTR (vorbis_parse_src_query)); - gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad); -} - -static void -vorbis_parse_set_header_on_caps (GstVorbisParse * parse, GstCaps * caps) -{ - GstBuffer *buf1, *buf2, *buf3; - GstStructure *structure; - GValue array = { 0 }; - GValue value = { 0 }; - - g_assert (parse); - g_assert (parse->streamheader); - g_assert (parse->streamheader->next); - g_assert (parse->streamheader->next->next); - buf1 = parse->streamheader->data; - g_assert (buf1); - buf2 = parse->streamheader->next->data; - g_assert (buf2); - buf3 = parse->streamheader->next->next->data; - g_assert (buf3); - - structure = gst_caps_get_structure (caps, 0); - - /* mark buffers */ - GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS); - GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS); - GST_BUFFER_FLAG_SET (buf3, GST_BUFFER_FLAG_IN_CAPS); - - /* put buffers in a fixed list */ - g_value_init (&array, GST_TYPE_ARRAY); - g_value_init (&value, GST_TYPE_BUFFER); - gst_value_set_buffer (&value, buf1); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - g_value_init (&value, GST_TYPE_BUFFER); - gst_value_set_buffer (&value, buf2); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - g_value_init (&value, GST_TYPE_BUFFER); - gst_value_set_buffer (&value, buf3); - gst_value_array_append_value (&array, &value); - gst_structure_set_value (structure, "streamheader", &array); - g_value_unset (&value); - g_value_unset (&array); -} - -static void -vorbis_parse_drain_event_queue (GstVorbisParse * parse) -{ - while (parse->event_queue->length) { - GstEvent *event; - - event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue)); - gst_pad_event_default (parse->sinkpad, event); - } -} - -static void -vorbis_parse_push_headers (GstVorbisParse * parse) -{ - /* mark and put on caps */ - GstCaps *caps; - GstBuffer *outbuf, *outbuf1, *outbuf2, *outbuf3; - ogg_packet packet; - - /* get the headers into the caps, passing them to vorbis as we go */ - caps = gst_caps_make_writable (gst_pad_get_caps (parse->srcpad)); - vorbis_parse_set_header_on_caps (parse, caps); - GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps); - gst_pad_set_caps (parse->srcpad, caps); - gst_caps_unref (caps); - - outbuf = GST_BUFFER_CAST (parse->streamheader->data); - packet.packet = GST_BUFFER_DATA (outbuf); - packet.bytes = GST_BUFFER_SIZE (outbuf); - packet.granulepos = GST_BUFFER_OFFSET_END (outbuf); - packet.packetno = 1; - packet.e_o_s = 0; - packet.b_o_s = 1; - vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet); - parse->sample_rate = parse->vi.rate; - outbuf1 = outbuf; - - outbuf = GST_BUFFER_CAST (parse->streamheader->next->data); - packet.packet = GST_BUFFER_DATA (outbuf); - packet.bytes = GST_BUFFER_SIZE (outbuf); - packet.granulepos = GST_BUFFER_OFFSET_END (outbuf); - packet.packetno = 2; - packet.e_o_s = 0; - packet.b_o_s = 0; - vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet); - outbuf2 = outbuf; - - outbuf = GST_BUFFER_CAST (parse->streamheader->next->next->data); - packet.packet = GST_BUFFER_DATA (outbuf); - packet.bytes = GST_BUFFER_SIZE (outbuf); - packet.granulepos = GST_BUFFER_OFFSET_END (outbuf); - packet.packetno = 3; - packet.e_o_s = 0; - packet.b_o_s = 0; - vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet); - outbuf3 = outbuf; - - /* first process queued events */ - vorbis_parse_drain_event_queue (parse); - - /* push out buffers, ignoring return value... */ - gst_buffer_set_caps (outbuf1, GST_PAD_CAPS (parse->srcpad)); - gst_pad_push (parse->srcpad, outbuf1); - gst_buffer_set_caps (outbuf2, GST_PAD_CAPS (parse->srcpad)); - gst_pad_push (parse->srcpad, outbuf2); - gst_buffer_set_caps (outbuf3, GST_PAD_CAPS (parse->srcpad)); - gst_pad_push (parse->srcpad, outbuf3); - - g_list_free (parse->streamheader); - parse->streamheader = NULL; - - parse->streamheader_sent = TRUE; -} - -static void -vorbis_parse_clear_queue (GstVorbisParse * parse) -{ - while (parse->buffer_queue->length) { - GstBuffer *buf; - - buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); - gst_buffer_unref (buf); - } - while (parse->event_queue->length) { - GstEvent *event; - - event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue)); - gst_event_unref (event); - } -} - -static GstFlowReturn -vorbis_parse_push_buffer (GstVorbisParse * parse, GstBuffer * buf, - gint64 granulepos) -{ - guint64 samples; - - /* our hack as noted below */ - samples = GST_BUFFER_OFFSET (buf); - - GST_BUFFER_OFFSET_END (buf) = granulepos; - GST_BUFFER_DURATION (buf) = samples * GST_SECOND / parse->sample_rate; - GST_BUFFER_OFFSET (buf) = granulepos * GST_SECOND / parse->sample_rate; - GST_BUFFER_TIMESTAMP (buf) = - GST_BUFFER_OFFSET (buf) - GST_BUFFER_DURATION (buf); - - gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad)); - - return gst_pad_push (parse->srcpad, buf); -} - -static GstFlowReturn -vorbis_parse_drain_queue_prematurely (GstVorbisParse * parse) -{ - GstFlowReturn ret = GST_FLOW_OK; - gint64 granulepos = MAX (parse->prev_granulepos, 0); - - /* got an EOS event, make sure to push out any buffers that were in the queue - * -- won't normally be the case, but this catches the - * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous - * stream. */ - - /* if we got EOS before any buffers came, go ahead and push the other events - * first */ - vorbis_parse_drain_event_queue (parse); - - while (!g_queue_is_empty (parse->buffer_queue)) { - GstBuffer *buf; - - buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); - - granulepos += GST_BUFFER_OFFSET (buf); - ret = vorbis_parse_push_buffer (parse, buf, granulepos); - - if (ret != GST_FLOW_OK) - goto done; - } - - parse->prev_granulepos = granulepos; - -done: - return ret; -} - -static GstFlowReturn -vorbis_parse_drain_queue (GstVorbisParse * parse, gint64 granulepos) -{ - GstFlowReturn ret = GST_FLOW_OK; - GList *walk; - gint64 cur = granulepos; - gint64 gp; - - for (walk = parse->buffer_queue->head; walk; walk = walk->next) - cur -= GST_BUFFER_OFFSET (walk->data); - - if (parse->prev_granulepos != -1) - cur = MAX (cur, parse->prev_granulepos); - - while (!g_queue_is_empty (parse->buffer_queue)) { - GstBuffer *buf; - - buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue)); - - cur += GST_BUFFER_OFFSET (buf); - gp = CLAMP (cur, 0, granulepos); - - ret = vorbis_parse_push_buffer (parse, buf, gp); - - if (ret != GST_FLOW_OK) - goto done; - } - - parse->prev_granulepos = granulepos; - -done: - return ret; -} - -static GstFlowReturn -vorbis_parse_queue_buffer (GstVorbisParse * parse, GstBuffer * buf) -{ - GstFlowReturn ret = GST_FLOW_OK; - long blocksize; - ogg_packet packet; - - buf = gst_buffer_make_metadata_writable (buf); - - packet.packet = GST_BUFFER_DATA (buf); - packet.bytes = GST_BUFFER_SIZE (buf); - packet.granulepos = GST_BUFFER_OFFSET_END (buf); - packet.packetno = parse->packetno + parse->buffer_queue->length; - packet.e_o_s = 0; - - blocksize = vorbis_packet_blocksize (&parse->vi, &packet); - - /* temporarily store the sample count in OFFSET -- we overwrite this later */ - - if (parse->prev_blocksize < 0) - GST_BUFFER_OFFSET (buf) = 0; - else - GST_BUFFER_OFFSET (buf) = (blocksize + parse->prev_blocksize) / 4; - - parse->prev_blocksize = blocksize; - - g_queue_push_tail (parse->buffer_queue, buf); - - if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) - ret = vorbis_parse_drain_queue (parse, GST_BUFFER_OFFSET_END (buf)); - - return ret; -} - -static GstFlowReturn -vorbis_parse_parse_packet (GstVorbisParse * parse, GstBuffer * buf) -{ - GstFlowReturn ret; - - parse->packetno++; - - if (parse->packetno <= 3) { - /* if 1 <= packetno <= 3, it's streamheader, - * so put it on the streamheader list and return */ - parse->streamheader = g_list_append (parse->streamheader, buf); - ret = GST_FLOW_OK; - } else { - if (!parse->streamheader_sent) - vorbis_parse_push_headers (parse); - - ret = vorbis_parse_queue_buffer (parse, buf); - } - - return ret; -} - -static GstFlowReturn -vorbis_parse_chain (GstPad * pad, GstBuffer * buffer) -{ - GstVorbisParseClass *klass; - GstVorbisParse *parse; - - parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad)); - klass = GST_VORBIS_PARSE_CLASS (G_OBJECT_GET_CLASS (parse)); - - g_assert (klass->parse_packet != NULL); - - return klass->parse_packet (parse, buffer); -} - -static gboolean -vorbis_parse_queue_event (GstVorbisParse * parse, GstEvent * event) -{ - GstFlowReturn ret = TRUE; - - g_queue_push_tail (parse->event_queue, event); - - return ret; -} - -static gboolean -vorbis_parse_sink_event (GstPad * pad, GstEvent * event) -{ - gboolean ret; - GstVorbisParse *parse; - - parse = GST_VORBIS_PARSE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - vorbis_parse_clear_queue (parse); - parse->prev_granulepos = -1; - parse->prev_blocksize = -1; - ret = gst_pad_event_default (pad, event); - break; - case GST_EVENT_EOS: - vorbis_parse_drain_queue_prematurely (parse); - ret = gst_pad_event_default (pad, event); - break; - default: - if (!parse->streamheader_sent && GST_EVENT_IS_SERIALIZED (event)) - ret = vorbis_parse_queue_event (parse, event); - else - ret = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (parse); - - return ret; -} - -static gboolean -vorbis_parse_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = TRUE; - GstVorbisParse *parse; - guint64 scale = 1; - - parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad)); - - /* fixme: assumes atomic access to lots of instance variables modified from - * the streaming thread, including 64-bit variables */ - - if (parse->packetno < 4) - return FALSE; - - if (src_format == *dest_format) { - *dest_value = src_value; - return TRUE; - } - - if (parse->sinkpad == pad && - (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES)) - return FALSE; - - switch (src_format) { - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_BYTES: - scale = sizeof (float) * parse->vi.channels; - case GST_FORMAT_DEFAULT: - *dest_value = - scale * gst_util_uint64_scale_int (src_value, parse->vi.rate, - GST_SECOND); - break; - default: - res = FALSE; - } - break; - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_BYTES: - *dest_value = src_value * sizeof (float) * parse->vi.channels; - break; - case GST_FORMAT_TIME: - *dest_value = - gst_util_uint64_scale_int (src_value, GST_SECOND, parse->vi.rate); - break; - default: - res = FALSE; - } - break; - case GST_FORMAT_BYTES: - switch (*dest_format) { - case GST_FORMAT_DEFAULT: - *dest_value = src_value / (sizeof (float) * parse->vi.channels); - break; - case GST_FORMAT_TIME: - *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND, - parse->vi.rate * sizeof (float) * parse->vi.channels); - break; - default: - res = FALSE; - } - break; - default: - res = FALSE; - } - - return res; -} - -static gboolean -vorbis_parse_src_query (GstPad * pad, GstQuery * query) -{ - gint64 granulepos; - GstVorbisParse *parse; - gboolean res = FALSE; - - parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - { - GstFormat format; - gint64 value; - - granulepos = parse->prev_granulepos; - - gst_query_parse_position (query, &format, NULL); - - /* and convert to the final format */ - if (!(res = - vorbis_parse_convert (pad, GST_FORMAT_DEFAULT, granulepos, - &format, &value))) - goto error; - - /* fixme: support segments - value = (value - parse->segment_start) + parse->segment_time; - */ - - gst_query_set_position (query, format, value); - - GST_LOG_OBJECT (parse, "query %p: peer returned granulepos: %" - G_GUINT64_FORMAT " - we return %" G_GUINT64_FORMAT " (format %u)", - query, granulepos, value, format); - - break; - } - case GST_QUERY_DURATION: - { - /* fixme: not threadsafe */ - /* query peer for total length */ - if (!gst_pad_is_linked (parse->sinkpad)) { - GST_WARNING_OBJECT (parse, "sink pad %" GST_PTR_FORMAT " is not linked", - parse->sinkpad); - goto error; - } - if (!(res = gst_pad_query (GST_PAD_PEER (parse->sinkpad), query))) - goto error; - break; - } - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - if (!(res = - vorbis_parse_convert (pad, src_fmt, src_val, &dest_fmt, - &dest_val))) - goto error; - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - return res; - -error: - { - GST_WARNING_OBJECT (parse, "error handling query"); - return res; - } -} - -static GstStateChangeReturn -vorbis_parse_change_state (GstElement * element, GstStateChange transition) -{ - GstVorbisParse *parse = GST_VORBIS_PARSE (element); - GstStateChangeReturn ret; - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - vorbis_info_init (&parse->vi); - vorbis_comment_init (&parse->vc); - parse->prev_granulepos = -1; - parse->prev_blocksize = -1; - parse->packetno = 0; - parse->streamheader_sent = FALSE; - parse->buffer_queue = g_queue_new (); - parse->event_queue = g_queue_new (); - break; - default: - break; - } - - ret = parent_class->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - vorbis_info_clear (&parse->vi); - vorbis_comment_clear (&parse->vc); - vorbis_parse_clear_queue (parse); - g_queue_free (parse->buffer_queue); - parse->buffer_queue = NULL; - g_queue_free (parse->event_queue); - parse->event_queue = NULL; - break; - default: - break; - } - - return ret; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/vorbis/vorbisparse.h --- a/gst_plugins_base/ext/vorbis/vorbisparse.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* -*- c-basic-offset: 2 -*- - * GStreamer - * Copyright (C) <2004> Thomas Vander Stichele - * - * 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. - */ - - -#ifndef __GST_VORBIS_PARSE_H__ -#define __GST_VORBIS_PARSE_H__ - - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_VORBIS_PARSE \ - (gst_vorbis_parse_get_type()) -#define GST_VORBIS_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VORBIS_PARSE,GstVorbisParse)) -#define GST_VORBIS_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VORBIS_PARSE,GstVorbisParseClass)) -#define GST_IS_VORBIS_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBIS_PARSE)) -#define GST_IS_VORBIS_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBIS_PARSE)) - -typedef struct _GstVorbisParse GstVorbisParse; -typedef struct _GstVorbisParseClass GstVorbisParseClass; - -/** - * GstVorbisParse: - * - * Opaque data structure. - */ -struct _GstVorbisParse { - GstElement element; - - GstPad * sinkpad; - GstPad * srcpad; - - guint packetno; - gboolean streamheader_sent; - GList * streamheader; - - GQueue * event_queue; - GQueue * buffer_queue; - - vorbis_info vi; - vorbis_comment vc; - - gint64 prev_granulepos; - gint32 prev_blocksize; - guint32 sample_rate; -}; - -struct _GstVorbisParseClass { - GstElementClass parent_class; - - /* virtual functions */ - GstFlowReturn (*parse_packet) (GstVorbisParse * parse, GstBuffer * buf); -}; - -GType gst_vorbis_parse_get_type(void); - -G_END_DECLS - -#endif /* __GST_VORBIS_PARSE_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/vorbis/vorbistag.c --- a/gst_plugins_base/ext/vorbis/vorbistag.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2006 James Livingston - * - * 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. - */ - -/** - * SECTION:element-vorbistag - * @see_also: #oggdemux, #oggmux, #vorbisparse, #GstTagSetter - * @short_description: retags vorbis streams - * - * - * - * The vorbistags element can change the tag contained within a raw - * vorbis stream. Specifically, it modifies the comments header packet - * of the vorbis stream. - * - * - * The element will also process the stream as the #vorbisparse element does - * so it can be used when remuxing an Ogg Vorbis stream, without additional - * elements. - * - * - * Applications can set the tags to write using the #GstTagSetter interface. - * Tags contained withing the vorbis bitstream will be picked up - * automatically (and merged according to the merge mode set via the tag - * setter interface). - * - * Example pipelines - * - * This element is not useful with gst-launch, because it does not support - * setting the tags on a #GstTagSetter interface. Conceptually, the element - * will usually be used like: - * - * gst-launch -v filesrc location=foo.ogg ! oggdemux ! vorbistag ! oggmux ! filesink location=bar.ogg - * - * - * - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include - -#include - -#include "vorbistag.h" - - -GST_DEBUG_CATEGORY_EXTERN (vorbisparse_debug); -#define GST_CAT_DEFAULT vorbisparse_debug - -static void gst_vorbis_tag_base_init (gpointer g_class); -static void gst_vorbis_tag_class_init (GstVorbisTagClass * klass); -static void gst_vorbis_tag_init (GstVorbisTag * tagger, - GstVorbisTagClass * g_class); -static GstFlowReturn gst_vorbis_tag_parse_packet (GstVorbisParse * parse, - GstBuffer * buffer); - -#define _do_init(type) \ - G_STMT_START{ \ - static const GInterfaceInfo tag_setter_info = { \ - NULL, \ - NULL, \ - NULL \ - }; \ - g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, \ - &tag_setter_info); \ - }G_STMT_END - -GST_BOILERPLATE_FULL (GstVorbisTag, gst_vorbis_tag, GstVorbisParse, - GST_TYPE_VORBIS_PARSE, _do_init); - -static GstElementDetails vorbis_tag_details = { - "VorbisTag", - "Formatter/Metadata", - "Retags vorbis streams", - "James Livingston " -}; - - -static void -gst_vorbis_tag_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &vorbis_tag_details); -} - -static void -gst_vorbis_tag_class_init (GstVorbisTagClass * klass) -{ - GstVorbisParseClass *vorbisparse_class = GST_VORBIS_PARSE_CLASS (klass); - - vorbisparse_class->parse_packet = gst_vorbis_tag_parse_packet; -} - -static void -gst_vorbis_tag_init (GstVorbisTag * tagger, GstVorbisTagClass * g_class) -{ - /* nothing to do */ -} - - -static GstFlowReturn -gst_vorbis_tag_parse_packet (GstVorbisParse * parse, GstBuffer * buffer) -{ - GstTagList *old_tags, *new_tags; - const GstTagList *user_tags; - GstVorbisTag *tagger; - gchar *encoder = NULL; - GstBuffer *new_buf; - - /* just pass everything except the comments packet */ - if (GST_BUFFER_SIZE (buffer) >= 1 && GST_BUFFER_DATA (buffer)[0] != 0x03) { - return GST_VORBIS_PARSE_CLASS (parent_class)->parse_packet (parse, buffer); - } - - tagger = GST_VORBIS_TAG (parse); - - old_tags = - gst_tag_list_from_vorbiscomment_buffer (buffer, (guint8 *) "\003vorbis", - 7, &encoder); - user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (tagger)); - - /* build new tag list */ - new_tags = gst_tag_list_merge (user_tags, old_tags, - gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (tagger))); - gst_tag_list_free (old_tags); - - new_buf = - gst_tag_list_to_vorbiscomment_buffer (new_tags, (guint8 *) "\003vorbis", - 7, encoder); - gst_buffer_copy_metadata (new_buf, buffer, GST_BUFFER_COPY_TIMESTAMPS); - - gst_tag_list_free (new_tags); - g_free (encoder); - gst_buffer_unref (buffer); - - return GST_VORBIS_PARSE_CLASS (parent_class)->parse_packet (parse, new_buf); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/ext/vorbis/vorbistag.h --- a/gst_plugins_base/ext/vorbis/vorbistag.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* -*- c-basic-offset: 2 -*- - * GStreamer - * Copyright (C) <2006> James Livingston - * - * 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. - */ - - -#ifndef __GST_VORBIS_TAG_H__ -#define __GST_VORBIS_TAG_H__ - -#include "vorbisparse.h" - - -G_BEGIN_DECLS - - -#define GST_TYPE_VORBIS_TAG \ - (gst_vorbis_tag_get_type()) -#define GST_VORBIS_TAG(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VORBIS_TAG,GstVorbisTag)) -#define GST_VORBIS_TAG_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VORBIS_TAG,GstVorbisTagClass)) -#define GST_IS_VORBIS_TAG(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBIS_TAG)) -#define GST_IS_VORBIS_TAG_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBIS_TAG)) - - -typedef struct _GstVorbisTag GstVorbisTag; -typedef struct _GstVorbisTagClass GstVorbisTagClass; - -/** - * GstVorbisTag: - * - * Opaque data structure. - */ -struct _GstVorbisTag { - GstVorbisParse parse; -}; - -struct _GstVorbisTagClass { - GstVorbisParseClass parent_class; -}; - -GType gst_vorbis_tag_get_type(void); - -G_END_DECLS - -#endif /* __GST_VORBIS_TAG_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/group/bld.inf --- a/gst_plugins_base/group/bld.inf Fri May 28 18:11:17 2010 -0500 +++ b/gst_plugins_base/group/bld.inf Fri Jun 25 17:18:46 2010 -0500 @@ -4,166 +4,166 @@ PRJ_EXPORTS // interfaces -../gst-libs/gst/interfaces/colorbalance.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/colorbalance.h -../gst-libs/gst/interfaces/colorbalancechannel.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/colorbalancechannel.h -../gst-libs/gst/interfaces/mixer.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/mixer.h -../gst-libs/gst/interfaces/mixeroptions.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/mixeroptions.h -../gst-libs/gst/interfaces/mixertrack.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/mixertrack.h -../gst-libs/gst/interfaces/navigation.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/navigation.h -../gst-libs/gst/interfaces/propertyprobe.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/propertyprobe.h -../gst-libs/gst/interfaces/tuner.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/tuner.h -../gst-libs/gst/interfaces/tunernorm.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/tunernorm.h -../gst-libs/gst/interfaces/tunerchannel.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/tunerchannel.h -../gst-libs/gst/interfaces/xoverlay.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/xoverlay.h -../gst-libs/gst/interfaces/interfaces-enumtypes.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/interfaces-enumtypes.h +../gst-libs/gst/interfaces/colorbalance.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/colorbalance.h) +../gst-libs/gst/interfaces/colorbalancechannel.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/colorbalancechannel.h) +../gst-libs/gst/interfaces/mixer.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/mixer.h) +../gst-libs/gst/interfaces/mixeroptions.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/mixeroptions.h) +../gst-libs/gst/interfaces/mixertrack.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/mixertrack.h) +../gst-libs/gst/interfaces/navigation.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/navigation.h) +../gst-libs/gst/interfaces/propertyprobe.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/propertyprobe.h) +../gst-libs/gst/interfaces/tuner.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/tuner.h) +../gst-libs/gst/interfaces/tunernorm.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/tunernorm.h) +../gst-libs/gst/interfaces/tunerchannel.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/tunerchannel.h) +../gst-libs/gst/interfaces/xoverlay.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/xoverlay.h) +../gst-libs/gst/interfaces/interfaces-enumtypes.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/interfaces/interfaces-enumtypes.h) // audio -../gst-libs/gst/audio/audio.h /epoc32/include/platform/mw/gstreamer/gst/audio/audio.h -../gst-libs/gst/audio/gstaudioclock.h /epoc32/include/platform/mw/gstreamer/gst/audio/gstaudioclock.h -../gst-libs/gst/audio/gstaudiofilter.h /epoc32/include/platform/mw/gstreamer/gst/audio/gstaudiofilter.h -../gst-libs/gst/audio/gstaudiosink.h /epoc32/include/platform/mw/gstreamer/gst/audio/gstaudiosink.h -../gst-libs/gst/audio/gstaudiosrc.h /epoc32/include/platform/mw/gstreamer/gst/audio/gstaudiosrc.h -../gst-libs/gst/audio/gstbaseaudiosink.h /epoc32/include/platform/mw/gstreamer/gst/audio/gstbaseaudiosink.h -../gst-libs/gst/audio/gstbaseaudiosrc.h /epoc32/include/platform/mw/gstreamer/gst/audio/gstbaseaudiosrc.h -../gst-libs/gst/audio/gstringbuffer.h /epoc32/include/platform/mw/gstreamer/gst/audio/gstringbuffer.h -../gst-libs/gst/audio/mixerutils.h /epoc32/include/platform/mw/gstreamer/gst/audio/mixerutils.h -../gst-libs/gst/audio/multichannel.h /epoc32/include/platform/mw/gstreamer/gst/audio/multichannel.h -../gst-libs/gst/audio/audio-enumtypes.h /epoc32/include/platform/mw/gstreamer/gst/audio/audio-enumtypes.h +../gst-libs/gst/audio/audio.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/audio.h) +../gst-libs/gst/audio/gstaudioclock.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/gstaudioclock.h) +../gst-libs/gst/audio/gstaudiofilter.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/gstaudiofilter.h) +../gst-libs/gst/audio/gstaudiosink.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/gstaudiosink.h) +../gst-libs/gst/audio/gstaudiosrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/gstaudiosrc.h) +../gst-libs/gst/audio/gstbaseaudiosink.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/gstbaseaudiosink.h) +../gst-libs/gst/audio/gstbaseaudiosrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/gstbaseaudiosrc.h) +../gst-libs/gst/audio/gstringbuffer.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/gstringbuffer.h) +../gst-libs/gst/audio/mixerutils.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/mixerutils.h) +../gst-libs/gst/audio/multichannel.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/multichannel.h) +../gst-libs/gst/audio/audio-enumtypes.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audio/audio-enumtypes.h) // cdda -//../gst-libs/gst/cdda/base64.h /epoc32/include/platform/mw/gstreamer/gst/cdda/base64.h -../gst-libs/gst/cdda/gstcddabasesrc.h /epoc32/include/platform/mw/gstreamer/gst/cdda/gstcddabasesrc.h +//../gst-libs/gst/cdda/base64.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/cdda/base64.h) +../gst-libs/gst/cdda/gstcddabasesrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/cdda/gstcddabasesrc.h) // floatcast -../gst-libs/gst/floatcast/floatcast.h /epoc32/include/platform/mw/gstreamer/gst/floatcast/floatcast.h +../gst-libs/gst/floatcast/floatcast.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/floatcast/floatcast.h) // riff -../gst-libs/gst/riff/riff-ids.h /epoc32/include/platform/mw/gstreamer/gst/riff/riff-ids.h -../gst-libs/gst/riff/riff-media.h /epoc32/include/platform/mw/gstreamer/gst/riff/riff-media.h -../gst-libs/gst/riff/riff-read.h /epoc32/include/platform/mw/gstreamer/gst/riff/riff-read.h +../gst-libs/gst/riff/riff-ids.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/riff/riff-ids.h) +../gst-libs/gst/riff/riff-media.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/riff/riff-media.h) +../gst-libs/gst/riff/riff-read.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/riff/riff-read.h) //app -../gst-libs/gst/app/gstappbuffer.h /epoc32/include/platform/mw/gstreamer/gst/app/gstappbuffer.h -../gst-libs/gst/app/gstappsink.h /epoc32/include/platform/mw/gstreamer/gst/app/gstappsink.h -../gst-libs/gst/app/gstappsrc.h /epoc32/include/platform/mw/gstreamer/gst/app/gstappsrc.h +../gst-libs/gst/app/gstappbuffer.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/app/gstappbuffer.h) +../gst-libs/gst/app/gstappsink.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/app/gstappsink.h) +../gst-libs/gst/app/gstappsrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/app/gstappsrc.h) // rtp -../gst-libs/gst/rtp/gstbasertpdepayload.h /epoc32/include/platform/mw/gstreamer/gst/rtp/gstbasertpdepayload.h -../gst-libs/gst/rtp/gstbasertppayload.h /epoc32/include/platform/mw/gstreamer/gst/rtp/gstbasertppayload.h -../gst-libs/gst/rtp/gstrtpbuffer.h /epoc32/include/platform/mw/gstreamer/gst/rtp/gstrtpbuffer.h -../gst-libs/gst/rtp/gstbasertpaudiopayload.h /epoc32/include/platform/mw/gstreamer/gst/rtp/gstbasertpaudiopayload.h -../gst-libs/gst/rtp/gstrtcpbuffer.h /epoc32/include/platform/mw/gstreamer/gst/rtp/gstrtcpbuffer.h -../gst-libs/gst/rtp/gstrtppayloads.h /epoc32/include/platform/mw/gstreamer/gst/rtp/gstrtppayloads.h +../gst-libs/gst/rtp/gstbasertpdepayload.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/rtp/gstbasertpdepayload.h) +../gst-libs/gst/rtp/gstbasertppayload.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/rtp/gstbasertppayload.h) +../gst-libs/gst/rtp/gstrtpbuffer.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/rtp/gstrtpbuffer.h) +../gst-libs/gst/rtp/gstbasertpaudiopayload.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/rtp/gstbasertpaudiopayload.h) +../gst-libs/gst/rtp/gstrtcpbuffer.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/rtp/gstrtcpbuffer.h) +../gst-libs/gst/rtp/gstrtppayloads.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/rtp/gstrtppayloads.h) // tag -//../gst-libs/gst/tag/gsttageditingprivate.h /epoc32/include/platform/mw/gstreamer/gst/tag/gsttageditingprivate.h -../gst-libs/gst/tag/tag.h /epoc32/include/platform/mw/gstreamer/gst/tag/tag.h +//../gst-libs/gst/tag/gsttageditingprivate.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tag/gsttageditingprivate.h) +../gst-libs/gst/tag/tag.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tag/tag.h) // netbuffer -../gst-libs/gst/netbuffer/gstnetbuffer.h /epoc32/include/platform/mw/gstreamer/gst/netbuffer/gstnetbuffer.h +../gst-libs/gst/netbuffer/gstnetbuffer.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/netbuffer/gstnetbuffer.h) // video -../gst-libs/gst/video/gstvideofilter.h /epoc32/include/platform/mw/gstreamer/gst/video/gstvideofilter.h -../gst-libs/gst/video/gstvideosink.h /epoc32/include/platform/mw/gstreamer/gst/video/gstvideosink.h -../gst-libs/gst/video/video.h /epoc32/include/platform/mw/gstreamer/gst/video/video.h -../gst-libs/gst/video/video-enumtypes.h /epoc32/include/platform/mw/gstreamer/gst/video/video-enumtypes.h +../gst-libs/gst/video/gstvideofilter.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/video/gstvideofilter.h) +../gst-libs/gst/video/gstvideosink.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/video/gstvideosink.h) +../gst-libs/gst/video/video.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/video/video.h) +../gst-libs/gst/video/video-enumtypes.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/video/video-enumtypes.h) // adder -//../gst/adder/gstadder.h /epoc32/include/platform/mw/gstreamer/gst/adder/gstadder.h +//../gst/adder/gstadder.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/adder/gstadder.h) // audioconvert -//../gst/audioconvert/audioconvert.h /epoc32/include/platform/mw/gstreamer/gst/audioconvert/audioconvert.h -//../gst/audioconvert/gstaudioconvert.h /epoc32/include/platform/mw/gstreamer/gst/audioconvert/gstaudioconvert.h -//../gst/audioconvert/gstchannelmix.h /epoc32/include/platform/mw/gstreamer/gst/audioconvert/gstchannelmix.h -//../gst/audioconvert/plugin.h /epoc32/include/platform/mw/gstreamer/gst/audioconvert/plugin.h +//../gst/audioconvert/audioconvert.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audioconvert/audioconvert.h) +//../gst/audioconvert/gstaudioconvert.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audioconvert/gstaudioconvert.h) +//../gst/audioconvert/gstchannelmix.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audioconvert/gstchannelmix.h) +//../gst/audioconvert/plugin.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audioconvert/plugin.h) // audioresample -//../gst/audioresample/buffer.h /epoc32/include/platform/mw/gstreamer/gst/audioresample/buffer.h -//../gst/audioresample/debug.h /epoc32/include/platform/mw/gstreamer/gst/audioresample/debug.h -//../gst/audioresample/functable.h /epoc32/include/platform/mw/gstreamer/gst/audioresample/functable.h -//../gst/audioresample/gstaudioresample.h /epoc32/include/platform/mw/gstreamer/gst/audioresample/gstaudioresample.h -//../gst/audioresample/resample.h /epoc32/include/platform/mw/gstreamer/gst/audioresample/resample.h +//../gst/audioresample/buffer.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audioresample/buffer.h) +//../gst/audioresample/debug.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audioresample/debug.h) +//../gst/audioresample/functable.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audioresample/functable.h) +//../gst/audioresample/gstaudioresample.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audioresample/gstaudioresample.h) +//../gst/audioresample/resample.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audioresample/resample.h) // audiotestsrc -//../gst/audiotestsrc/gstaudiotestsrc.h /epoc32/include/platform/mw/gstreamer/gst/audiotestsrc/gstaudiotestsrc.h +//../gst/audiotestsrc/gstaudiotestsrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/audiotestsrc/gstaudiotestsrc.h) // ffmpegcolorspace -//../gst/ffmpegcolorspace/avcodec.h /epoc32/include/platform/mw/gstreamer/gst/ffmpegcolorspace/avcodec.h -//../gst/ffmpegcolorspace/dsputil.h /epoc32/include/platform/mw/gstreamer/gst/ffmpegcolorspace/dsputil.h -//../gst/ffmpegcolorspace/gstffmpegcodecmap.h /epoc32/include/platform/mw/gstreamer/gst/ffmpegcolorspace/gstffmpegcodecmap.h -//../gst/ffmpegcolorspace/gstffmpegcolorspace.h /epoc32/include/platform/mw/gstreamer/gst/ffmpegcolorspace/gstffmpegcolorspace.h -//../gst/ffmpegcolorspace/imgconvert_template.h /epoc32/include/platform/mw/gstreamer/gst/ffmpegcolorspace/imgconvert_template.h +//../gst/ffmpegcolorspace/avcodec.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/ffmpegcolorspace/avcodec.h) +//../gst/ffmpegcolorspace/dsputil.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/ffmpegcolorspace/dsputil.h) +//../gst/ffmpegcolorspace/gstffmpegcodecmap.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/ffmpegcolorspace/gstffmpegcodecmap.h) +//../gst/ffmpegcolorspace/gstffmpegcolorspace.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/ffmpegcolorspace/gstffmpegcolorspace.h) +//../gst/ffmpegcolorspace/imgconvert_template.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/ffmpegcolorspace/imgconvert_template.h) // playback -//../gst/playback/gstplay-marshal.h /epoc32/include/platform/mw/gstreamer/gst/playback/gstplay-marshal.h -//../gst/playback/gstplaybasebin.h /epoc32/include/platform/mw/gstreamer/gst/playback/gstplaybasebin.h -//../gst/playback/gststreaminfo.h /epoc32/include/platform/mw/gstreamer/gst/playback/gststreaminfo.h -//../gst/playback/gststreamselector.h /epoc32/include/platform/mw/gstreamer/gst/playback/gststreamselector.h +//../gst/playback/gstplay-marshal.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/playback/gstplay-marshal.h) +//../gst/playback/gstplaybasebin.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/playback/gstplaybasebin.h) +//../gst/playback/gststreaminfo.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/playback/gststreaminfo.h) +//../gst/playback/gststreamselector.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/playback/gststreamselector.h) //pbutils -../gst-libs/gst/pbutils/pbutils.h /epoc32/include/platform/mw/gstreamer/gst/pbutils/pbutils.h -../gst-libs/gst/pbutils/descriptions.h /epoc32/include/platform/mw/gstreamer/gst/pbutils/descriptions.h -../gst-libs/gst/pbutils/install-plugins.h /epoc32/include/platform/mw/gstreamer/gst/pbutils/install-plugins.h -../gst-libs/gst/pbutils/missing-plugins.h /epoc32/include/platform/mw/gstreamer/gst/pbutils/missing-plugins.h -../gst-libs/gst/pbutils/pbutils-enumtypes.h /epoc32/include/platform/mw/gstreamer/gst/pbutils/pbutils-enumtypes.h +../gst-libs/gst/pbutils/pbutils.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/pbutils/pbutils.h) +../gst-libs/gst/pbutils/descriptions.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/pbutils/descriptions.h) +../gst-libs/gst/pbutils/install-plugins.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/pbutils/install-plugins.h) +../gst-libs/gst/pbutils/missing-plugins.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/pbutils/missing-plugins.h) +../gst-libs/gst/pbutils/pbutils-enumtypes.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/pbutils/pbutils-enumtypes.h) // subparse -//../gst/subparse/gstssaparse.h /epoc32/include/platform/mw/gstreamer/gst/subparse/gstssaparse.h -//../gst/subparse/gstsubparse.h /epoc32/include/platform/mw/gstreamer/gst/subparse/gstsubparse.h -//../gst/subparse/samiparse.h /epoc32/include/platform/mw/gstreamer/gst/subparse/samiparse.h +//../gst/subparse/gstssaparse.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/subparse/gstssaparse.h) +//../gst/subparse/gstsubparse.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/subparse/gstsubparse.h) +//../gst/subparse/samiparse.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/subparse/samiparse.h) // tcp -//../gst/tcp/gstmultifdsink.h /epoc32/include/platform/mw/gstreamer/gst/tcp/gstmultifdsink.h -//../gst/tcp/gsttcp-enumtypes.h /epoc32/include/platform/mw/gstreamer/gst/tcp/gsttcp-enumtypes.h -//../gst/tcp/gsttcp-marshal.h /epoc32/include/platform/mw/gstreamer/gst/tcp/gsttcp-marshal.h -//../gst/tcp/gsttcp.h /epoc32/include/platform/mw/gstreamer/gst/tcp/gsttcp.h -//../gst/tcp/gsttcpclientsink.h /epoc32/include/platform/mw/gstreamer/gst/tcp/gsttcpclientsink.h -//../gst/tcp/gsttcpclientsrc.h /epoc32/include/platform/mw/gstreamer/gst/tcp/gsttcpclientsrc.h -//../gst/tcp/gsttcpplugin.h /epoc32/include/platform/mw/gstreamer/gst/tcp/gsttcpplugin.h -//../gst/tcp/gsttcpserversink.h /epoc32/include/platform/mw/gstreamer/gst/tcp/gsttcpserversink.h -//../gst/tcp/gsttcpserversrc.h /epoc32/include/platform/mw/gstreamer/gst/tcp/gsttcpserversrc.h +//../gst/tcp/gstmultifdsink.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tcp/gstmultifdsink.h) +//../gst/tcp/gsttcp-enumtypes.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tcp/gsttcp-enumtypes.h) +//../gst/tcp/gsttcp-marshal.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tcp/gsttcp-marshal.h) +//../gst/tcp/gsttcp.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tcp/gsttcp.h) +//../gst/tcp/gsttcpclientsink.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tcp/gsttcpclientsink.h) +//../gst/tcp/gsttcpclientsrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tcp/gsttcpclientsrc.h) +//../gst/tcp/gsttcpplugin.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tcp/gsttcpplugin.h) +//../gst/tcp/gsttcpserversink.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tcp/gsttcpserversink.h) +//../gst/tcp/gsttcpserversrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/tcp/gsttcpserversrc.h) // videorate -//../gst/videorate/gstvideorate.h /epoc32/include/platform/mw/gstreamer/gst/videorate/gstvideorate.h +//../gst/videorate/gstvideorate.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/videorate/gstvideorate.h) // videoscale -//../gst/videoscale/gstvideoscale.h /epoc32/include/platform/mw/gstreamer/gst/videoscale/gstvideoscale.h -//../gst/videoscale/vs_image.h /epoc32/include/platform/mw/gstreamer/gst/videoscale/vs_image.h -//../gst/videoscale/vs_scanline.h /epoc32/include/platform/mw/gstreamer/gst/videoscale/vs_scanline.h +//../gst/videoscale/gstvideoscale.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/videoscale/gstvideoscale.h) +//../gst/videoscale/vs_image.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/videoscale/vs_image.h) +//../gst/videoscale/vs_scanline.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/videoscale/vs_scanline.h) // videotestsrc -//../gst/videotestsrc/gstvideotestsrc.h /epoc32/include/platform/mw/gstreamer/gst/videotestsrc/gstvideotestsrc.h -//../gst/videotestsrc/videotestsrc.h /epoc32/include/platform/mw/gstreamer/gst/videotestsrc/videotestsrc.h +//../gst/videotestsrc/gstvideotestsrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/videotestsrc/gstvideotestsrc.h) +//../gst/videotestsrc/videotestsrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/videotestsrc/videotestsrc.h) // volume -//../gst/volume/gstvolume.h /epoc32/include/platform/mw/gstreamer/gst/volume/gstvolume.h +//../gst/volume/gstvolume.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/volume/gstvolume.h) //liboil - Since liboil port is available, No need to use liboil stub. -//../gst/oil/liboil.h /epoc32/include/platform/mw/gstreamer/gst/liboil.h +//../gst/oil/liboil.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/liboil.h) // fft -//../gst-libs/gst/fft/_kiss_fft_guts_f32.h /epoc32/include/platform/mw/gstreamer/gst/fft/_kiss_fft_guts_f32.h -//../gst-libs/gst/fft/_kiss_fft_guts_f64.h /epoc32/include/platform/mw/gstreamer/gst/fft/_kiss_fft_guts_f64.h -//../gst-libs/gst/fft/_kiss_fft_guts_s16.h /epoc32/include/platform/mw/gstreamer/gst/fft/_kiss_fft_guts_s16.h -//../gst-libs/gst/fft/_kiss_fft_guts_s32.h /epoc32/include/platform/mw/gstreamer/gst/fft/_kiss_fft_guts_s32.h -../gst-libs/gst/fft/gstfft.h /epoc32/include/platform/mw/gstreamer/gst/fft/gstfft.h -../gst-libs/gst/fft/gstfftf32.h /epoc32/include/platform/mw/gstreamer/gst/fft/gstfftf32.h -../gst-libs/gst/fft/gstfftf64.h /epoc32/include/platform/mw/gstreamer/gst/fft/gstfftf64.h -../gst-libs/gst/fft/gstffts16.h /epoc32/include/platform/mw/gstreamer/gst/fft/gstffts16.h -../gst-libs/gst/fft/gstffts32.h /epoc32/include/platform/mw/gstreamer/gst/fft/gstffts32.h -//../gst-libs/gst/fft/kiss_fft_f32.h /epoc32/include/platform/mw/gstreamer/gst/fft/kiss_fft_f32.h -//../gst-libs/gst/fft/kiss_fft_f64.h /epoc32/include/platform/mw/gstreamer/gst/fft/kiss_fft_f64.h -//../gst-libs/gst/fft/kiss_fft_s16.h /epoc32/include/platform/mw/gstreamer/gst/fft/kiss_fft_s16.h -//../gst-libs/gst/fft/kiss_fft_s32.h /epoc32/include/platform/mw/gstreamer/gst/fft/kiss_fft_s32.h -//../gst-libs/gst/fft/kiss_fftr_f32.h /epoc32/include/platform/mw/gstreamer/gst/fft/kiss_fftr_f32.h -//../gst-libs/gst/fft/kiss_fftr_f64.h /epoc32/include/platform/mw/gstreamer/gst/fft/kiss_fftr_f64.h -//../gst-libs/gst/fft/kiss_fftr_s16.h /epoc32/include/platform/mw/gstreamer/gst/fft/kiss_fftr_s16.h -//../gst-libs/gst/fft/kiss_fftr_s32.h /epoc32/include/platform/mw/gstreamer/gst/fft/kiss_fftr_s32.h +//../gst-libs/gst/fft/_kiss_fft_guts_f32.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/_kiss_fft_guts_f32.h) +//../gst-libs/gst/fft/_kiss_fft_guts_f64.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/_kiss_fft_guts_f64.h) +//../gst-libs/gst/fft/_kiss_fft_guts_s16.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/_kiss_fft_guts_s16.h) +//../gst-libs/gst/fft/_kiss_fft_guts_s32.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/_kiss_fft_guts_s32.h) +../gst-libs/gst/fft/gstfft.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/gstfft.h) +../gst-libs/gst/fft/gstfftf32.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/gstfftf32.h) +../gst-libs/gst/fft/gstfftf64.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/gstfftf64.h) +../gst-libs/gst/fft/gstffts16.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/gstffts16.h) +../gst-libs/gst/fft/gstffts32.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/gstffts32.h) +//../gst-libs/gst/fft/kiss_fft_f32.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/kiss_fft_f32.h) +//../gst-libs/gst/fft/kiss_fft_f64.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/kiss_fft_f64.h) +//../gst-libs/gst/fft/kiss_fft_s16.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/kiss_fft_s16.h) +//../gst-libs/gst/fft/kiss_fft_s32.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/kiss_fft_s32.h) +//../gst-libs/gst/fft/kiss_fftr_f32.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/kiss_fftr_f32.h) +//../gst-libs/gst/fft/kiss_fftr_f64.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/kiss_fftr_f64.h) +//../gst-libs/gst/fft/kiss_fftr_s16.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/kiss_fftr_s16.h) +//../gst-libs/gst/fft/kiss_fftr_s32.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/fft/kiss_fftr_s32.h) //internationalization macros -//../gst-libs/gst/gst-i18n-plugin.h /epoc32/include/platform/mw/gstreamer/gst/gst-i18n-plugin.h +//../gst-libs/gst/gst-i18n-plugin.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gst-i18n-plugin.h) //avcodec -//../gst/ffmpegcolorspace/avcodec.h /epoc32/include/platform/mw/gstreamer/gst/avcodec.h +//../gst/ffmpegcolorspace/avcodec.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/avcodec.h) PRJ_MMPFILES diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/gst/oil/liboil.h --- a/gst_plugins_base/gst/oil/liboil.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -#ifndef __LIBOIL__ -#define __LIBOIL__ - -#include -#include - -IMPORT_C void resample_linear_u8_ref (uint8_t *dest, uint8_t *src, int n, uint32_t *in); -IMPORT_C void resample_linear_argb_ref (uint32_t *d, uint32_t *s, int n, uint32_t *in); -IMPORT_C void merge_linear_argb_ref (uint32_t *d, uint32_t *s1, uint32_t *s2, uint32_t *src3, int n); -//IMPORT_C void splat_u8_ref (uint8_t *dest, int dstr, uint8_t *param, int n); -IMPORT_C void oil_scalarmultiply_f32_ns (float * d, const float * s1, const float * s2_1, int n); -IMPORT_C void oil_merge_linear_argb (uint32_t * d_n, const uint32_t * s_n, const uint32_t * s2_n, const uint32_t * s3_1, int n); -IMPORT_C void oil_merge_linear_u8 (uint8_t * d_n, const uint8_t * s_n, const uint8_t * s2_n, const uint32_t * s3_1, int n); -IMPORT_C void oil_resample_linear_argb (uint32_t * d_n, const uint32_t * s_2xn, int n, uint32_t * i_2); -IMPORT_C void oil_resample_linear_u8 (uint8_t * d_n, const uint8_t * s_2xn, int n, uint32_t * i_2); -IMPORT_C void oil_splat_u8 (uint8_t * dest, int dstr, const uint8_t * s1_1, int n); -IMPORT_C void oil_splat_u8_ns (uint8_t * dest, const uint8_t * s1_1, int n); - -#endif diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/gst/oil/stub.c --- a/gst_plugins_base/gst/oil/stub.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,501 +0,0 @@ -#include"liboil.h" - -//Arun's changes -typedef struct _OilFunctionImpl OilFunctionImpl; -typedef struct _OilFunctionClass OilFunctionClass; -typedef void (*OilTestFunction) (OilFunctionClass *klass,OilFunctionImpl *impl); - -#define OIL_CHECK_PROTOTYPE(a) -/** - * OilFunctionClass: - * - * An opaque structure representing a function class. - * - */ -struct _OilFunctionClass { - /*< private >*/ - void *func; - const char *name; - const char *desc; - OilTestFunction test_func; - - OilFunctionImpl *first_impl; - OilFunctionImpl *reference_impl; - - OilFunctionImpl *chosen_impl; - - const char *prototype; -}; - - -/** - * OilFunctionImpl: - * - * An opaque structure representing a function implementation. - * - */ -struct _OilFunctionImpl { - /*< private >*/ - void *next; - OilFunctionClass *klass; - void *func; - unsigned int flags; - const char *name; - double profile_ave; - double profile_std; -}; - -#ifndef OIL_NO_CLASSES -/** - * OIL_DEFINE_CLASS_FULL: - * @klass: name of class to declare (without oil_ prefix) - * @string: prototype of class - * @test: test function - * - * Defines a #OilFunctionClass structure for @klass. Classes - * defined this way will be automatically at Liboil initialization - * time. - */ - -#define OIL_DEFINE_CLASS_FULL(klass, string, test) \ -OilFunctionClass _oil_function_class_ ## klass = { \ - NULL, \ - #klass , \ - NULL, \ - test, \ - NULL, \ - NULL, \ - NULL, \ - string \ -}; \ -OilFunctionClass *oil_function_class_ptr_ ## klass = \ - &_oil_function_class_ ## klass -#else -#define OIL_DEFINE_CLASS_FULL(klass, string, test) \ - OIL_DECLARE_CLASS(klass) -#endif - -/** - * OIL_DEFINE_CLASS: - * @klass: name of class to declare (without oil_ prefix) - * @string: prototype of class - * - * Defines a #OilFunctionClass structure for @klass. Classes - * defined this way will be automatically at Liboil initialization - * time. - */ -#define OIL_DEFINE_CLASS(klass, string) \ - OIL_DEFINE_CLASS_FULL (klass, string, NULL) - - -OIL_DEFINE_CLASS (scalarmultiply_f32_ns, "float *d, float *s1, float *s2_1, int n"); - -OIL_DEFINE_CLASS_FULL (resample_linear_argb, - "uint32_t *d_n, uint32_t *s_2xn, int n, uint32_t *i_2", - NULL); - -OIL_DEFINE_CLASS_FULL (resample_linear_u8, - "uint8_t *d_n, uint8_t *s_2xn, int n, uint32_t *i_2", - NULL); - -OIL_DEFINE_CLASS_FULL (merge_linear_argb, - "uint32_t *d_n, uint32_t *s_n, uint32_t *s2_n, uint32_t *s3_1, int n", - NULL); -OIL_DEFINE_CLASS_FULL (merge_linear_u8, - "uint8_t *d_n, uint8_t *s_n, uint8_t *s2_n, uint32_t *s3_1, int n", - NULL); - -OIL_DEFINE_CLASS(splat_u8_ns,"uint8_t *dest, uint8_t *s1_1, int n"); - -OIL_DEFINE_CLASS(splat_u8,"uint8_t *dest, int dstr, uint8_t *s1_1, int n"); - -typedef enum { - OIL_IMPL_FLAG_REF = (1<<0), - OIL_IMPL_FLAG_OPT = (1<<1), - OIL_IMPL_FLAG_ASM = (1<<2), - OIL_IMPL_FLAG_DISABLED = (1<<3), - OIL_IMPL_FLAG_CMOV = (1<<16), - OIL_IMPL_FLAG_MMX = (1<<17), - OIL_IMPL_FLAG_SSE = (1<<18), - OIL_IMPL_FLAG_MMXEXT = (1<<19), - OIL_IMPL_FLAG_SSE2 = (1<<20), - OIL_IMPL_FLAG_3DNOW = (1<<21), - OIL_IMPL_FLAG_3DNOWEXT = (1<<22), - OIL_IMPL_FLAG_SSE3 = (1<<23), - OIL_IMPL_FLAG_ALTIVEC = (1<<24), - OIL_IMPL_FLAG_EDSP = (1<<25), - OIL_IMPL_FLAG_ARM6 = (1<<26), - OIL_IMPL_FLAG_VFP = (1<<27), - OIL_IMPL_FLAG_SSSE3 = (1<<28) -} OilImplFlag; - -#ifndef OIL_OPT_MANGLE -#define OIL_OPT_MANGLE(a) a -#define OIL_OPT_FLAG_MANGLE(a) a -#else -#define OIL_NO_CLASSES -#define OIL_OPT_FLAG_MANGLE(a) (((a)&(~OIL_IMPL_FLAG_REF)) | OIL_IMPL_FLAG_OPT) -#endif -#ifndef OIL_OPT_SUFFIX -#define OIL_OPT_SUFFIX -#endif - -/** - * OIL_DEFINE_IMPL_FULL: - * @function: name of function - * @klass: name of class to declare (without oil_ prefix) - * @flags: implementation flags and CPU requirements - * - * Defines a #OilFunctionImpl structure for the function @function - * and class @klass. CPU-dependent flags in @flags will indicate - * that this implementation requires the given CPU flags. - */ -#define OIL_DEFINE_IMPL_FULL(function,klass,flags) \ -OilFunctionImpl OIL_OPT_MANGLE(_oil_function_impl_ ## function) = { \ - NULL, \ - &_oil_function_class_ ## klass , \ - (void *)function, \ - OIL_OPT_FLAG_MANGLE(flags), \ - #function OIL_OPT_SUFFIX \ -} \ -OIL_CHECK_PROTOTYPE(;_oil_type_ ## klass _ignore_me_ ## function = function) - -/** - * OIL_DEFINE_IMPL: - * @function: name of function - * @klass: name of class to declare (without oil_ prefix) - * - * Shorthand for defining a C implementation. See OIL_DEFINE_IMPL_FULL(). - */ -#define OIL_DEFINE_IMPL(function,klass) \ - OIL_DEFINE_IMPL_FULL(function,klass,0) -/** - * OIL_DEFINE_IMPL_REF: - * @function: name of function - * @klass: name of class to declare (without oil_ prefix) - * - * Shorthand for defining a reference implementation. See OIL_DEFINE_IMPL_FULL(). - */ -#define OIL_DEFINE_IMPL_REF(function,klass) \ - OIL_DEFINE_IMPL_FULL(function,klass,OIL_IMPL_FLAG_REF) - - - - -typedef void (*_oil_type_scalarmultiply_f32_ns)(float * d, const float * s1, const float * s2_1, int n); -//#define oil_scalarmultiply_f32_ns ((_oil_type_scalarmultiply_f32_ns)(*(void **)oil_function_class_ptr_scalarmultiply_f32_ns)) - - - -#define OIL_GET(ptr, offset, type) (*(type *)((uint8_t *)(ptr) + (offset)) ) - -/**************'_oil_resample_linear_u8'****************************/ -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - - -static void -resample_linear_u8_ref (uint8_t *dest, uint8_t *src, int n, - uint32_t *in) -{ - int acc = in[0]; - int increment = in[1]; - int i; - int j; - int x; - - for(i=0;i>16; - x = (acc&0xffff)>>8; - dest[i] = (src[j]*(256-x) + src[j+1]*x) >> 8; - - acc += increment; - } - - in[0] = acc; -} - -/************************'_oil_resample_linear_argb'***************************/ -static void -resample_linear_argb_ref (uint32_t *d, uint32_t *s, int n, uint32_t *in) -{ - uint8_t *src = (uint8_t *)s; - uint8_t *dest = (uint8_t *)d; - int acc = in[0]; - int increment = in[1]; - int i; - int j; - int x; - - for(i=0;i>16; - x = (acc&0xffff)>>8; - dest[4*i+0] = (src[4*j+0]*(256-x) + src[4*j+4]*x) >> 8; - dest[4*i+1] = (src[4*j+1]*(256-x) + src[4*j+5]*x) >> 8; - dest[4*i+2] = (src[4*j+2]*(256-x) + src[4*j+6]*x) >> 8; - dest[4*i+3] = (src[4*j+3]*(256-x) + src[4*j+7]*x) >> 8; - - acc += increment; - } - - in[0] = acc; -} - -/****************** '_oil_merge_linear_argb'**************************/ -static void -merge_linear_argb_ref (uint32_t *d, uint32_t *s1, uint32_t *s2, - uint32_t *src3, int n) -{ - uint8_t *src1 = (uint8_t *)s1; - uint8_t *src2 = (uint8_t *)s2; - uint8_t *dest = (uint8_t *)d; - int i; - int x = src3[0]; - - for(i=0;i> 8; - dest[4*i+1] = (src1[4*i+1]*(256-x) + src2[4*i+1]*x) >> 8; - dest[4*i+2] = (src1[4*i+2]*(256-x) + src2[4*i+2]*x) >> 8; - dest[4*i+3] = (src1[4*i+3]*(256-x) + src2[4*i+3]*x) >> 8; - } -} - -static void -merge_linear_u8_ref (uint8_t *dest, uint8_t *src1, uint8_t *src2, - uint32_t *src3, int n) -{ - int i; - int x = src3[0]; - - for(i=0;i> 8; - } -} - -static void splat_u8_ref (uint8_t *dest, int dstr, uint8_t *param, int n) -{ - int i; - for(i=0;iflags & OIL_CPU_FLAG_MASK) & (~oil_cpu_flags)) - return 0; - return 1; -} - -/** - * oil_class_optimize: - * @klass: a function class - * - * Tests and profiles each implementation for the given function - * class. Testing compares the output of running each implementation - * on random input against the reference implementation for the - * same input. - */ -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - -void -oil_class_optimize (OilFunctionClass * klass) -{ - OilFunctionImpl *impl; - OilFunctionImpl *min_impl; - int ret; - - - if (klass->reference_impl == NULL) { - return; - } - if (klass->first_impl == NULL) { - return; - } - - min_impl = NULL; - - for (impl = klass->first_impl; impl; impl = impl->next) { - if (!oil_impl_is_runnable (impl)) - continue; - } - - if (min_impl == NULL) { - return; - } - - klass->chosen_impl = min_impl; - klass->func = min_impl->func; - -} - - -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - void oil_scalarmultiply_f32_ns (float * d, const float * s1, const float * s2_1, int n) -{ - /* - if (_oil_function_class_scalarmultiply_f32_ns.func == NULL) { - oil_class_optimize (&_oil_function_class_scalarmultiply_f32_ns); - } - */ - scalarmultiply_f32_ns_ref(d,(float*) s1,(float*) s2_1, n); - //((void (*)(float * d, const float * s1, const float * s2_1, int n))(_oil_function_class_scalarmultiply_f32_ns.func))(d, s1, s2_1, n); -} -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - - void -oil_merge_linear_argb (uint32_t * d_n, const uint32_t * s_n, const uint32_t * s2_n, const uint32_t * s3_1, int n) -{ - if (_oil_function_class_merge_linear_argb.func == NULL) { - oil_class_optimize (&_oil_function_class_merge_linear_argb); - } - ((void (*)(uint32_t * d_n, const uint32_t * s_n, const uint32_t * s2_n, const uint32_t * s3_1, int n))(_oil_function_class_merge_linear_argb.func))(d_n, s_n, s2_n, s3_1, n); -} -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - void -oil_merge_linear_u8 (uint8_t * d_n, const uint8_t * s_n, const uint8_t * s2_n, const uint32_t * s3_1, int n) -{ - if (_oil_function_class_merge_linear_u8.func == NULL) { - oil_class_optimize (&_oil_function_class_merge_linear_u8); - } - ((void (*)(uint8_t * d_n, const uint8_t * s_n, const uint8_t * s2_n, const uint32_t * s3_1, int n))(_oil_function_class_merge_linear_u8.func))(d_n, s_n, s2_n, s3_1, n); -} -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - - - void -oil_resample_linear_argb (uint32_t * d_n, const uint32_t * s_2xn, int n, uint32_t * i_2) -{ - if (_oil_function_class_resample_linear_argb.func == NULL) { - oil_class_optimize (&_oil_function_class_resample_linear_argb); - } - ((void (*)(uint32_t * d_n, const uint32_t * s_2xn, int n, uint32_t * i_2))(_oil_function_class_resample_linear_argb.func))(d_n, s_2xn, n, i_2); -} -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - void -oil_resample_linear_u8 (uint8_t * d_n, const uint8_t * s_2xn, int n, uint32_t * i_2) -{ - if (_oil_function_class_resample_linear_u8.func == NULL) { - oil_class_optimize (&_oil_function_class_resample_linear_u8); - } - ((void (*)(uint8_t * d_n, const uint8_t * s_2xn, int n, uint32_t * i_2))(_oil_function_class_resample_linear_u8.func))(d_n, s_2xn, n, i_2); -} -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - - - void -oil_splat_u8 (uint8_t * dest, int dstr, const uint8_t * s1_1, int n) -{ - if (_oil_function_class_splat_u8.func == NULL) { - oil_class_optimize (&_oil_function_class_splat_u8); - } - ((void (*)(uint8_t * dest, int dstr, const uint8_t * s1_1, int n))(_oil_function_class_splat_u8.func))(dest, dstr, s1_1, n); -} -#ifdef __SYMBIAN32__ -EXPORT_C -#endif - -void -oil_splat_u8_ns (uint8_t * dest, const uint8_t * s1_1, int n) -{ - if (_oil_function_class_splat_u8_ns.func == NULL) { - oil_class_optimize (&_oil_function_class_splat_u8_ns); - } - ((void (*)(uint8_t * dest, const uint8_t * s1_1, int n))(_oil_function_class_splat_u8_ns.func))(dest, s1_1, n); -} - -OIL_DEFINE_IMPL_REF (scalarmultiply_f32_ns_ref, scalarmultiply_f32_ns); -OIL_DEFINE_IMPL_REF (resample_linear_u8_ref, resample_linear_u8); -OIL_DEFINE_IMPL_REF (resample_linear_argb_ref, resample_linear_argb); -OIL_DEFINE_IMPL_REF (merge_linear_argb_ref, merge_linear_argb); -OIL_DEFINE_IMPL_REF (merge_linear_u8_ref, merge_linear_u8); -OIL_DEFINE_IMPL_REF(splat_u8_ref, splat_u8); -OIL_DEFINE_IMPL_REF(splat_u8_ns_ref, splat_u8_ns); - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4l.c --- a/gst_plugins_base/sys/v4l/gstv4l.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* GStreamer - * - * gstv4l.c: plugin for v4l elements - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gst/gst-i18n-plugin.h" - -#include - -#include "gstv4lelement.h" -#include "gstv4lsrc.h" -/* #include "gstv4ljpegsrc.h" */ -/* #include "gstv4lmjpegsrc.h" */ -/* #include "gstv4lmjpegsink.h" */ - -GST_DEBUG_CATEGORY (v4l_debug); /* used in v4l_calls.c and v4lsrc_calls.c */ - -static gboolean -plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (v4l_debug, "v4l", 0, "V4L API calls"); - - if (!gst_element_register (plugin, "v4lsrc", GST_RANK_NONE, GST_TYPE_V4LSRC)) -/* !gst_element_register (plugin, "v4ljpegsrc", */ -/* GST_RANK_NONE, GST_TYPE_V4LJPEGSRC) || */ -/* !gst_element_register (plugin, "v4lmjpegsrc", */ -/* GST_RANK_NONE, GST_TYPE_V4LMJPEGSRC) || */ -/* !gst_element_register (plugin, "v4lmjpegsink", */ -/* GST_RANK_NONE, GST_TYPE_V4LMJPEGSINK)) */ - return FALSE; - -#ifdef ENABLE_NLS - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); -#endif /* ENABLE_NLS */ - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "video4linux", - "elements for Video 4 Linux", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4lcolorbalance.c --- a/gst_plugins_base/sys/v4l/gstv4lcolorbalance.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/* GStreamer - * - * gstv4lcolorbalance.c: color balance interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include "gstv4lcolorbalance.h" -#include "gstv4lelement.h" - -static void -gst_v4l_color_balance_channel_class_init (GstV4lColorBalanceChannelClass * - klass); -static void gst_v4l_color_balance_channel_init (GstV4lColorBalanceChannel * - channel); - -static const GList *gst_v4l_color_balance_list_channels (GstColorBalance * - balance); -static void gst_v4l_color_balance_set_value (GstColorBalance * balance, - GstColorBalanceChannel * channel, gint value); -static gint gst_v4l_color_balance_get_value (GstColorBalance * balance, - GstColorBalanceChannel * channel); - -static GstColorBalanceChannelClass *parent_class = NULL; - -GType -gst_v4l_color_balance_channel_get_type (void) -{ - static GType gst_v4l_color_balance_channel_type = 0; - - if (!gst_v4l_color_balance_channel_type) { - static const GTypeInfo v4l_tuner_channel_info = { - sizeof (GstV4lColorBalanceChannelClass), - NULL, - NULL, - (GClassInitFunc) gst_v4l_color_balance_channel_class_init, - NULL, - NULL, - sizeof (GstV4lColorBalanceChannel), - 0, - (GInstanceInitFunc) gst_v4l_color_balance_channel_init, - NULL - }; - - gst_v4l_color_balance_channel_type = - g_type_register_static (GST_TYPE_COLOR_BALANCE_CHANNEL, - "GstV4lColorBalanceChannel", &v4l_tuner_channel_info, 0); - } - - return gst_v4l_color_balance_channel_type; -} - -static void -gst_v4l_color_balance_channel_class_init (GstV4lColorBalanceChannelClass * - klass) -{ - parent_class = g_type_class_peek_parent (klass); -} - -static void -gst_v4l_color_balance_channel_init (GstV4lColorBalanceChannel * channel) -{ - channel->index = 0; -} - -void -gst_v4l_color_balance_interface_init (GstColorBalanceClass * klass) -{ - GST_COLOR_BALANCE_TYPE (klass) = GST_COLOR_BALANCE_HARDWARE; - - /* default virtual functions */ - klass->list_channels = gst_v4l_color_balance_list_channels; - klass->set_value = gst_v4l_color_balance_set_value; - klass->get_value = gst_v4l_color_balance_get_value; -} - -static G_GNUC_UNUSED gboolean -gst_v4l_color_balance_contains_channel (GstV4lElement * v4lelement, - GstV4lColorBalanceChannel * v4lchannel) -{ - const GList *item; - - for (item = v4lelement->colors; item != NULL; item = item->next) - if (item->data == v4lchannel) - return TRUE; - - return FALSE; -} - -static const GList * -gst_v4l_color_balance_list_channels (GstColorBalance * balance) -{ - return GST_V4LELEMENT (balance)->colors; -} - -static void -gst_v4l_color_balance_set_value (GstColorBalance * balance, - GstColorBalanceChannel * channel, gint value) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (balance); - GstV4lColorBalanceChannel *v4lchannel = - GST_V4L_COLOR_BALANCE_CHANNEL (channel); - - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); - g_return_if_fail (gst_v4l_color_balance_contains_channel (v4lelement, - v4lchannel)); - - gst_v4l_set_picture (v4lelement, v4lchannel->index, value); -} - -static gint -gst_v4l_color_balance_get_value (GstColorBalance * balance, - GstColorBalanceChannel * channel) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (balance); - GstV4lColorBalanceChannel *v4lchannel = - GST_V4L_COLOR_BALANCE_CHANNEL (channel); - gint value; - - /* assert that we're opened and that we're using a known item */ - g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), 0); - g_return_val_if_fail (gst_v4l_color_balance_contains_channel (v4lelement, - v4lchannel), 0); - - if (!gst_v4l_get_picture (v4lelement, v4lchannel->index, &value)) - return 0; - - return value; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4lcolorbalance.h --- a/gst_plugins_base/sys/v4l/gstv4lcolorbalance.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* GStreamer - * - * gstv4lcolorbalance.h: color balance interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje - * - * 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. - */ - -#ifndef __GST_V4L_COLOR_BALANCE_H__ -#define __GST_V4L_COLOR_BALANCE_H__ - -#include -#include -#include "v4l_calls.h" - -G_BEGIN_DECLS - -#define GST_TYPE_V4L_COLOR_BALANCE_CHANNEL \ - (gst_v4l_color_balance_channel_get_type ()) -#define GST_V4L_COLOR_BALANCE_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L_COLOR_BALANCE_CHANNEL, \ - GstV4lColorBalanceChannel)) -#define GST_V4L_COLOR_BALANCE_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L_COLOR_BALANCE_CHANNEL, \ - GstV4lColorBalanceChannelClass)) -#define GST_IS_V4L_COLOR_BALANCE_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L_COLOR_BALANCE_CHANNEL)) -#define GST_IS_V4L_COLOR_BALANCE_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L_COLOR_BALANCE_CHANNEL)) - -typedef struct _GstV4lColorBalanceChannel { - GstColorBalanceChannel parent; - - GstV4lPictureType index; -} GstV4lColorBalanceChannel; - -typedef struct _GstV4lColorBalanceChannelClass { - GstColorBalanceChannelClass parent; -} GstV4lColorBalanceChannelClass; - -GType gst_v4l_color_balance_channel_get_type (void); - -void gst_v4l_color_balance_interface_init (GstColorBalanceClass *klass); - -#endif /* __GST_V4L_COLOR_BALANCE_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4lelement.c --- a/gst_plugins_base/sys/v4l/gstv4lelement.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,470 +0,0 @@ -/* GStreamer - * - * gstv4lelement.c: base class for V4L elements - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include - -#include "v4l_calls.h" -#include "gstv4ltuner.h" -#ifdef HAVE_XVIDEO -#include "gstv4lxoverlay.h" -#endif -#include "gstv4lcolorbalance.h" - - -enum -{ - PROP_0, - PROP_DEVICE, - PROP_DEVICE_NAME, - PROP_FLAGS -}; - - -static void gst_v4lelement_init_interfaces (GType type); - -GST_BOILERPLATE_FULL (GstV4lElement, gst_v4lelement, GstPushSrc, - GST_TYPE_PUSH_SRC, gst_v4lelement_init_interfaces); - - -static void gst_v4lelement_dispose (GObject * object); -static void gst_v4lelement_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_v4lelement_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_v4lelement_start (GstBaseSrc * src); -static gboolean gst_v4lelement_stop (GstBaseSrc * src); - - -static gboolean -gst_v4l_iface_supported (GstImplementsInterface * iface, GType iface_type) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (iface); - -#ifdef HAVE_XVIDEO - g_assert (iface_type == GST_TYPE_TUNER || - iface_type == GST_TYPE_X_OVERLAY || iface_type == GST_TYPE_COLOR_BALANCE); -#else - g_assert (iface_type == GST_TYPE_TUNER || - iface_type == GST_TYPE_COLOR_BALANCE); -#endif - - if (v4lelement->video_fd == -1) - return FALSE; - -#ifdef HAVE_XVIDEO - if (iface_type == GST_TYPE_X_OVERLAY && !GST_V4L_IS_OVERLAY (v4lelement)) - return FALSE; -#endif - - return TRUE; -} - -static void -gst_v4l_interface_init (GstImplementsInterfaceClass * klass) -{ - /* default virtual functions */ - klass->supported = gst_v4l_iface_supported; -} - -static const GList * -gst_v4l_probe_get_properties (GstPropertyProbe * probe) -{ - GObjectClass *klass = G_OBJECT_GET_CLASS (probe); - static GList *list = NULL; - - if (!list) { - list = g_list_append (NULL, g_object_class_find_property (klass, "device")); - } - - return list; -} - -static gboolean -gst_v4l_class_probe_devices (GstV4lElementClass * klass, gboolean check) -{ - static gboolean init = FALSE; - static GList *devices = NULL; - - if (!init && !check) { - gchar *dev_base[] = { "/dev/video", "/dev/v4l/video", NULL }; - gint base, n, fd; - - while (devices) { - GList *item = devices; - gchar *device = item->data; - - devices = g_list_remove (devices, item); - g_free (device); - } - - /* detect /dev entries */ - for (n = 0; n < 64; n++) { - for (base = 0; dev_base[base] != NULL; base++) { - struct stat s; - gchar *device = g_strdup_printf ("%s%d", dev_base[base], n); - - /* does the /dev/ entry exist at all? */ - if (stat (device, &s) == 0) { - /* yes: is a device attached? */ - if ((fd = open (device, O_RDONLY)) > 0 || errno == EBUSY) { - if (fd > 0) - close (fd); - - devices = g_list_append (devices, device); - break; - } - } - g_free (device); - } - } - - init = TRUE; - } - - klass->devices = devices; - - return init; -} - -static void -gst_v4l_probe_probe_property (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstV4lElementClass *klass = GST_V4LELEMENT_GET_CLASS (probe); - - switch (prop_id) { - case PROP_DEVICE: - gst_v4l_class_probe_devices (klass, FALSE); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } -} - -static gboolean -gst_v4l_probe_needs_probe (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstV4lElementClass *klass = GST_V4LELEMENT_GET_CLASS (probe); - gboolean ret = FALSE; - - switch (prop_id) { - case PROP_DEVICE: - ret = !gst_v4l_class_probe_devices (klass, TRUE); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return ret; -} - -static GValueArray * -gst_v4l_class_list_devices (GstV4lElementClass * klass) -{ - GValueArray *array; - GValue value = { 0 }; - GList *item; - - if (!klass->devices) - return NULL; - - array = g_value_array_new (g_list_length (klass->devices)); - item = klass->devices; - g_value_init (&value, G_TYPE_STRING); - while (item) { - gchar *device = item->data; - - g_value_set_string (&value, device); - g_value_array_append (array, &value); - - item = item->next; - } - g_value_unset (&value); - - return array; -} - -static GValueArray * -gst_v4l_probe_get_values (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstV4lElementClass *klass = GST_V4LELEMENT_GET_CLASS (probe); - GValueArray *array = NULL; - - switch (prop_id) { - case PROP_DEVICE: - array = gst_v4l_class_list_devices (klass); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return array; -} - -static void -gst_v4l_property_probe_interface_init (GstPropertyProbeInterface * iface) -{ - iface->get_properties = gst_v4l_probe_get_properties; - iface->probe_property = gst_v4l_probe_probe_property; - iface->needs_probe = gst_v4l_probe_needs_probe; - iface->get_values = gst_v4l_probe_get_values; -} - -#define GST_TYPE_V4L_DEVICE_FLAGS (gst_v4l_device_get_type ()) -static GType -gst_v4l_device_get_type (void) -{ - static GType v4l_device_type = 0; - - if (v4l_device_type == 0) { - static const GFlagsValue values[] = { - {VID_TYPE_CAPTURE, "CAPTURE", "Device can capture"}, - {VID_TYPE_TUNER, "TUNER", "Device has a tuner"}, - {VID_TYPE_OVERLAY, "OVERLAY", "Device can do overlay"}, - {VID_TYPE_MPEG_DECODER, "MPEG_DECODER", "Device can decode MPEG"}, - {VID_TYPE_MPEG_ENCODER, "MPEG_ENCODER", "Device can encode MPEG"}, - {VID_TYPE_MJPEG_DECODER, "MJPEG_DECODER", "Device can decode MJPEG"}, - {VID_TYPE_MJPEG_ENCODER, "MJPEG_ENCODER", "Device can encode MJPEG"}, - {0x10000, "AUDIO", "Device handles audio"}, - {0, NULL, NULL} - }; - - v4l_device_type = g_flags_register_static ("GstV4lDeviceTypeFlags", values); - } - - return v4l_device_type; -} - -static void -gst_v4lelement_init_interfaces (GType type) -{ - static const GInterfaceInfo v4liface_info = { - (GInterfaceInitFunc) gst_v4l_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo v4l_tuner_info = { - (GInterfaceInitFunc) gst_v4l_tuner_interface_init, - NULL, - NULL, - }; -#ifdef HAVE_XVIDEO - static const GInterfaceInfo v4l_xoverlay_info = { - (GInterfaceInitFunc) gst_v4l_xoverlay_interface_init, - NULL, - NULL, - }; -#endif - static const GInterfaceInfo v4l_colorbalance_info = { - (GInterfaceInitFunc) gst_v4l_color_balance_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo v4l_propertyprobe_info = { - (GInterfaceInitFunc) gst_v4l_property_probe_interface_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, - GST_TYPE_IMPLEMENTS_INTERFACE, &v4liface_info); - g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l_tuner_info); -#ifdef HAVE_XVIDEO - g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l_xoverlay_info); -#endif - g_type_add_interface_static (type, - GST_TYPE_COLOR_BALANCE, &v4l_colorbalance_info); - g_type_add_interface_static (type, - GST_TYPE_PROPERTY_PROBE, &v4l_propertyprobe_info); -} - - -static void -gst_v4lelement_base_init (gpointer g_class) -{ - GstV4lElementClass *klass = GST_V4LELEMENT_CLASS (g_class); - - klass->devices = NULL; -} - -static void -gst_v4lelement_class_init (GstV4lElementClass * klass) -{ - GObjectClass *gobject_class; - GstBaseSrcClass *basesrc_class; - - gobject_class = (GObjectClass *) klass; - basesrc_class = (GstBaseSrcClass *) klass; - - gobject_class->set_property = gst_v4lelement_set_property; - gobject_class->get_property = gst_v4lelement_get_property; - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE, - g_param_spec_string ("device", "Device", "Device location", - NULL, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE_NAME, - g_param_spec_string ("device_name", "Device name", "Name of the device", - NULL, G_PARAM_READABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FLAGS, - g_param_spec_flags ("flags", "Flags", "Device type flags", - GST_TYPE_V4L_DEVICE_FLAGS, 0, G_PARAM_READABLE)); - - basesrc_class->start = gst_v4lelement_start; - basesrc_class->stop = gst_v4lelement_stop; - - gobject_class->dispose = gst_v4lelement_dispose; -} - - -static void -gst_v4lelement_init (GstV4lElement * v4lelement, GstV4lElementClass * klass) -{ - /* some default values */ - v4lelement->video_fd = -1; - v4lelement->buffer = NULL; - v4lelement->videodev = g_strdup ("/dev/video0"); - - v4lelement->norms = NULL; - v4lelement->channels = NULL; - v4lelement->colors = NULL; - - v4lelement->xwindow_id = 0; -} - - -static void -gst_v4lelement_dispose (GObject * object) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (object); - - if (v4lelement->videodev) { - g_free (v4lelement->videodev); - v4lelement->videodev = NULL; - } - - if (((GObjectClass *) parent_class)->dispose) - ((GObjectClass *) parent_class)->dispose (object); -} - - -static void -gst_v4lelement_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (object); - - switch (prop_id) { - case PROP_DEVICE: - if (v4lelement->videodev) - g_free (v4lelement->videodev); - v4lelement->videodev = g_strdup (g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -gst_v4lelement_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (object); - - switch (prop_id) { - case PROP_DEVICE: - g_value_set_string (value, v4lelement->videodev); - break; - case PROP_DEVICE_NAME:{ - gchar *new = NULL; - - if (GST_V4L_IS_OPEN (v4lelement)) { - new = v4lelement->vcap.name; - } else if (gst_v4l_open (v4lelement)) { - new = v4lelement->vcap.name; - gst_v4l_close (v4lelement); - } - g_value_set_string (value, new); - break; - } - case PROP_FLAGS:{ - guint flags = 0; - - if (GST_V4L_IS_OPEN (v4lelement)) { - flags |= v4lelement->vcap.type & 0x3C0B; - if (v4lelement->vcap.audios) - flags |= 0x10000; - } - g_value_set_flags (value, flags); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gst_v4lelement_start (GstBaseSrc * src) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (src); - - if (!gst_v4l_open (v4lelement)) - return FALSE; - -#ifdef HAVE_XVIDEO - gst_v4l_xoverlay_start (v4lelement); -#endif - - return TRUE; -} - -static gboolean -gst_v4lelement_stop (GstBaseSrc * src) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (src); - -#ifdef HAVE_XVIDEO - gst_v4l_xoverlay_stop (v4lelement); -#endif - - if (!gst_v4l_close (v4lelement)) - return FALSE; - - return TRUE; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4lelement.h --- a/gst_plugins_base/sys/v4l/gstv4lelement.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/* GStreamer - * - * gstv4lelement.h: base class for V4L elements - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifndef __GST_V4LELEMENT_H__ -#define __GST_V4LELEMENT_H__ - -/* Because of some really cool feature in video4linux1, also known as - * 'not including sys/types.h and sys/time.h', we had to include it - * ourselves. In all their intelligence, these people decided to fix - * this in the next version (video4linux2) in such a cool way that it - * breaks all compilations of old stuff... - * The real problem is actually that linux/time.h doesn't use proper - * macro checks before defining types like struct timeval. The proper - * fix here is to either fuck the kernel header (which is what we do - * by defining _LINUX_TIME_H, an innocent little hack) or by fixing it - * upstream, which I'll consider doing later on. If you get compiler - * errors here, check your linux/time.h && sys/time.h header setup. - */ -#include -#define _LINUX_TIME_H -#include - -#include -#include - - -G_BEGIN_DECLS - -#define GST_TYPE_V4LELEMENT \ - (gst_v4lelement_get_type()) -#define GST_V4LELEMENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LELEMENT,GstV4lElement)) -#define GST_V4LELEMENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LELEMENT,GstV4lElementClass)) -#define GST_IS_V4LELEMENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LELEMENT)) -#define GST_IS_V4LELEMENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LELEMENT)) -#define GST_V4LELEMENT_GET_CLASS(klass) \ - (G_TYPE_INSTANCE_GET_CLASS ((klass), GST_TYPE_V4LELEMENT, GstV4lElementClass)) - -typedef struct _GstV4lElement GstV4lElement; -typedef struct _GstV4lElementClass GstV4lElementClass; -typedef struct _GstV4lXv GstV4lXv; - -struct _GstV4lElement { - GstPushSrc element; - - /* the video device */ - char *videodev; - - /* the video-device's file descriptor */ - gint video_fd; - - /* the video buffer (mmap()'ed) */ - guint8 *buffer; - - /* the video device's capabilities */ - struct video_capability vcap; - - /* the video device's window properties */ - struct video_window vwin; - - /* some more info about the current input's capabilities */ - struct video_channel vchan; - - /* lists... */ - GList *colors; - GList *norms; - GList *channels; - - /* X-overlay */ - GstV4lXv *xv; - gulong xwindow_id; -}; - -struct _GstV4lElementClass { - GstPushSrcClass parent_class; - - /* probed devices */ - GList *devices; - - /* actions */ - gboolean (*get_attribute) (GstElement *element, - const gchar *attr_name, - int *value); - gboolean (*set_attribute) (GstElement *element, - const gchar *attr_name, - const int value); -}; - -GType gst_v4lelement_get_type(void); - - -G_END_DECLS - -#endif /* __GST_V4LELEMENT_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4ljpegsrc.h --- a/gst_plugins_base/sys/v4l/gstv4ljpegsrc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* GStreamer - * - * gstv4ljpegsrc.h: V4L video source element for JPEG cameras - * - * Copyright (C) 2001-2005 Jan Schmidt - * - * 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. - */ - -#ifndef __GST_V4LJPEGSRC_H__ -#define __GST_V4LJPEGSRC_H__ - -#include - -G_BEGIN_DECLS -#define GST_TYPE_V4LJPEGSRC \ - (gst_v4ljpegsrc_get_type()) -#define GST_V4LJPEGSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LJPEGSRC,GstV4lJpegSrc)) -#define GST_V4LJPEGSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LJPEGSRC,GstV4lJpegSrcClass)) -#define GST_IS_V4LJPEGSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LJPEGSRC)) -#define GST_IS_V4LJPEGSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LJPEGSRC)) -typedef struct _GstV4lJpegSrc GstV4lJpegSrc; -typedef struct _GstV4lJpegSrcClass GstV4lJpegSrcClass; - -struct _GstV4lJpegSrc -{ - GstV4lSrc v4lsrc; - GstPadGetFunction getfn; - GstPadGetCapsFunction getcapsfn; -}; - -struct _GstV4lJpegSrcClass -{ - GstV4lSrcClass parent_class; -}; - -GType gst_v4ljpegsrc_get_type (void); - -G_END_DECLS -#endif /* __GST_V4LJPEGSRC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4lmjpegsink.h --- a/gst_plugins_base/sys/v4l/gstv4lmjpegsink.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* GStreamer - * - * gstv4lmjpegsink.h: hardware MJPEG video sink element - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifndef __GST_V4LMJPEGSINK_H__ -#define __GST_V4LMJPEGSINK_H__ - -#include -#include -#include - - -G_BEGIN_DECLS - - -#define GST_TYPE_V4LMJPEGSINK \ - (gst_v4lmjpegsink_get_type()) -#define GST_V4LMJPEGSINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LMJPEGSINK,GstV4lMjpegSink)) -#define GST_V4LMJPEGSINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LMJPEGSINK,GstV4lMjpegSinkClass)) -#define GST_IS_V4LMJPEGSINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LMJPEGSINK)) -#define GST_IS_V4LMJPEGSINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LMJPEGSINK)) - -typedef struct _GstV4lMjpegSink GstV4lMjpegSink; -typedef struct _GstV4lMjpegSinkClass GstV4lMjpegSinkClass; - -struct _GstV4lMjpegSink { - GstV4lElement v4lelement; - - /* the sink pas */ - GstPad *sinkpad; - - /* frame properties for common players */ - gint frames_displayed; - guint64 frame_time; - - /* system clock object */ - GstClock *clock; - - /* buffer/capture info */ - struct mjpeg_sync bsync; - struct mjpeg_requestbuffers breq; - - /* thread to keep track of synced frames */ - gint8 *isqueued_queued_frames; /* 1 = queued, 0 = unqueued, -1 = error */ - GThread *thread_queued_frames; - GMutex *mutex_queued_frames; - GCond **cond_queued_frames; - gint current_frame; - - /* width/height/norm of the jpeg stream */ - gint width; - gint height; - gint norm; - - /* cache values */ - gint x_offset; - gint y_offset; - - gint numbufs; - gint bufsize; /* in KB */ -}; - -struct _GstV4lMjpegSinkClass { - GstV4lElementClass parent_class; - - /* signals */ - void (*frame_displayed) (GstElement *element); -}; - -GType gst_v4lmjpegsink_get_type(void); - - -G_END_DECLS - -#endif /* __GST_SDLVIDEOSINK_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4lmjpegsrc.h --- a/gst_plugins_base/sys/v4l/gstv4lmjpegsrc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/* GStreamer - * - * gstv4lmjpegsrc.h: hardware MJPEG video source element - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifndef __GST_V4LMJPEGSRC_H__ -#define __GST_V4LMJPEGSRC_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_V4LMJPEGSRC \ - (gst_v4lmjpegsrc_get_type()) -#define GST_V4LMJPEGSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LMJPEGSRC,GstV4lMjpegSrc)) -#define GST_V4LMJPEGSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LMJPEGSRC,GstV4lMjpegSrcClass)) -#define GST_IS_V4LMJPEGSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LMJPEGSRC)) -#define GST_IS_V4LMJPEGSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LMJPEGSRC)) - -typedef struct _GstV4lMjpegSrc GstV4lMjpegSrc; -typedef struct _GstV4lMjpegSrcClass GstV4lMjpegSrcClass; - -struct _GstV4lMjpegSrc { - GstV4lElement v4lelement; - - /* pads */ - GstPad *srcpad; - - /* buffer/capture info */ - struct mjpeg_sync bsync; - struct mjpeg_requestbuffers breq; - - /* num of queued frames and some GThread stuff - * to wait if there's not enough */ - gint8 *frame_queue_state; - GMutex *mutex_queue_state; - GCond *cond_queue_state; - gint num_queued; - gint queue_frame; - - /* True if we want to stop */ - gboolean quit, is_capturing; - - /* A/V sync... frame counter and internal cache */ - gulong handled; - gint last_frame; - gint last_size; - gint need_writes; - gulong last_seq; - - /* clock */ - GstClock *clock; - - /* time to substract from clock time to get back to timestamp */ - GstClockTime substract_time; - - /* how often are we going to use each frame? */ - gint *use_num_times; - - /* how are we going to push buffers? */ - gboolean use_fixed_fps; - - /* end size */ - gint end_width, end_height; - - /* caching values */ -#if 0 - gint x_offset; - gint y_offset; - gint frame_width; - gint frame_height; -#endif - - gint quality; - gint numbufs; -}; - -struct _GstV4lMjpegSrcClass { - GstV4lElementClass parent_class; - - void (*frame_capture) (GObject *object); - void (*frame_drop) (GObject *object); - void (*frame_insert) (GObject *object); - void (*frame_lost) (GObject *object, - gint num_lost); -}; - -GType gst_v4lmjpegsrc_get_type(void); - - -G_END_DECLS - -#endif /* __GST_V4LMJPEGSRC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4lsrc.c --- a/gst_plugins_base/sys/v4l/gstv4lsrc.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,732 +0,0 @@ -/* GStreamer - * - * gstv4lsrc.c: BT8x8/V4L source element - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include "v4lsrc_calls.h" -#include - - -static const GstElementDetails gst_v4lsrc_details = -GST_ELEMENT_DETAILS ("Video (video4linux/raw) Source", - "Source/Video", - "Reads raw frames from a video4linux device", - "Ronald Bultje "); - - -GST_DEBUG_CATEGORY_STATIC (v4lsrc_debug); -#define GST_CAT_DEFAULT v4lsrc_debug - - -enum -{ - PROP_0, - PROP_AUTOPROBE, - PROP_AUTOPROBE_FPS, - PROP_COPY_MODE, - PROP_TIMESTAMP_OFFSET -}; - - -GST_BOILERPLATE (GstV4lSrc, gst_v4lsrc, GstV4lElement, GST_TYPE_V4LELEMENT); - - -/* basesrc methods */ -static gboolean gst_v4lsrc_start (GstBaseSrc * src); -static gboolean gst_v4lsrc_stop (GstBaseSrc * src); -static gboolean gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps); -static GstCaps *gst_v4lsrc_get_caps (GstBaseSrc * src); -static GstFlowReturn gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** out); -static gboolean gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query); -static void gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps); - -static void gst_v4lsrc_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_v4lsrc_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - - -static void -gst_v4lsrc_base_init (gpointer g_class) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (gstelement_class, &gst_v4lsrc_details); - - gst_element_class_add_pad_template (gstelement_class, - gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - gst_caps_new_any ())); -} - -static void -gst_v4lsrc_class_init (GstV4lSrcClass * klass) -{ - GObjectClass *gobject_class; - GstBaseSrcClass *basesrc_class; - GstPushSrcClass *pushsrc_class; - - gobject_class = (GObjectClass *) klass; - basesrc_class = (GstBaseSrcClass *) klass; - pushsrc_class = (GstPushSrcClass *) klass; - - gobject_class->set_property = gst_v4lsrc_set_property; - gobject_class->get_property = gst_v4lsrc_get_property; - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE, - g_param_spec_boolean ("autoprobe", "Autoprobe", - "Whether the device should be probed for all possible features", - TRUE, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE_FPS, - g_param_spec_boolean ("autoprobe-fps", "Autoprobe FPS", - "Whether the device should be probed for framerates", - TRUE, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COPY_MODE, - g_param_spec_boolean ("copy-mode", "Copy mode", - "Whether to send out copies of buffers, or direct pointers to the mmap region", - TRUE, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset", - "Timestamp offset", - "A time offset subtracted from timestamps set on buffers (in ns)", - G_MININT64, G_MAXINT64, 0, G_PARAM_READWRITE)); - - GST_DEBUG_CATEGORY_INIT (v4lsrc_debug, "v4lsrc", 0, "V4L source element"); - - basesrc_class->get_caps = gst_v4lsrc_get_caps; - basesrc_class->set_caps = gst_v4lsrc_set_caps; - basesrc_class->start = gst_v4lsrc_start; - basesrc_class->stop = gst_v4lsrc_stop; - basesrc_class->fixate = gst_v4lsrc_fixate; - basesrc_class->query = gst_v4lsrc_query; - - pushsrc_class->create = gst_v4lsrc_create; -} - -static void -gst_v4lsrc_init (GstV4lSrc * v4lsrc, GstV4lSrcClass * klass) -{ - v4lsrc->buffer_size = 0; - - /* no colorspaces */ - v4lsrc->colorspaces = NULL; - - v4lsrc->is_capturing = FALSE; - v4lsrc->autoprobe = TRUE; - v4lsrc->autoprobe_fps = TRUE; - v4lsrc->copy_mode = TRUE; - - v4lsrc->timestamp_offset = 0; - - v4lsrc->fps_list = NULL; - - gst_base_src_set_format (GST_BASE_SRC (v4lsrc), GST_FORMAT_TIME); - gst_base_src_set_live (GST_BASE_SRC (v4lsrc), TRUE); -} - -static void -gst_v4lsrc_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstV4lSrc *v4lsrc = GST_V4LSRC (object); - - switch (prop_id) { - case PROP_AUTOPROBE: - g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc))); - v4lsrc->autoprobe = g_value_get_boolean (value); - break; - case PROP_AUTOPROBE_FPS: - g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc))); - v4lsrc->autoprobe_fps = g_value_get_boolean (value); - break; - case PROP_COPY_MODE: - v4lsrc->copy_mode = g_value_get_boolean (value); - break; - case PROP_TIMESTAMP_OFFSET: - v4lsrc->timestamp_offset = g_value_get_int64 (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -gst_v4lsrc_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstV4lSrc *v4lsrc = GST_V4LSRC (object); - - switch (prop_id) { - case PROP_AUTOPROBE: - g_value_set_boolean (value, v4lsrc->autoprobe); - break; - case PROP_AUTOPROBE_FPS: - g_value_set_boolean (value, v4lsrc->autoprobe_fps); - break; - case PROP_COPY_MODE: - g_value_set_boolean (value, v4lsrc->copy_mode); - break; - case PROP_TIMESTAMP_OFFSET: - g_value_set_int64 (value, v4lsrc->timestamp_offset); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* this function is a bit of a last resort */ -static void -gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps) -{ - GstStructure *structure; - int i; - int targetwidth, targetheight; - GstV4lSrc *v4lsrc = GST_V4LSRC (bsrc); - struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap; - struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin; - - if (GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) { - GST_DEBUG_OBJECT (v4lsrc, "device reported w: %d-%d, h: %d-%d", - vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight); - targetwidth = vcap->minwidth; - targetheight = vcap->minheight; - /* if we can get the current vwin settings, we use those to fixate */ - if (!gst_v4l_get_capabilities (GST_V4LELEMENT (v4lsrc))) - GST_DEBUG_OBJECT (v4lsrc, "failed getting capabilities"); - else { - targetwidth = vwin->width; - targetheight = vwin->height; - } - } else { - GST_DEBUG_OBJECT (v4lsrc, "device closed, guessing"); - targetwidth = 320; - targetheight = 200; - } - - GST_DEBUG_OBJECT (v4lsrc, "targetting %dx%d", targetwidth, targetheight); - - for (i = 0; i < gst_caps_get_size (caps); ++i) { - const GValue *v; - - structure = gst_caps_get_structure (caps, i); - gst_structure_fixate_field_nearest_int (structure, "width", targetwidth); - gst_structure_fixate_field_nearest_int (structure, "height", targetheight); - gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2); - - v = gst_structure_get_value (structure, "format"); - if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) { - guint32 fourcc; - - g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST); - - fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0)); - gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL); - } - } -} - -static gint all_palettes[] = { - VIDEO_PALETTE_YUV422, - VIDEO_PALETTE_YUV420P, - VIDEO_PALETTE_UYVY, - VIDEO_PALETTE_YUV411P, - VIDEO_PALETTE_YUV422P, - VIDEO_PALETTE_YUV410P, - VIDEO_PALETTE_YUV411, - VIDEO_PALETTE_RGB555, - VIDEO_PALETTE_RGB565, - VIDEO_PALETTE_RGB24, - VIDEO_PALETTE_RGB32, - -1 -}; - -static GstCaps * -gst_v4lsrc_palette_to_caps (int palette) -{ - guint32 fourcc; - GstCaps *caps; - - switch (palette) { - case VIDEO_PALETTE_YUV422: - case VIDEO_PALETTE_YUYV: - fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'); - break; - case VIDEO_PALETTE_YUV420P: - fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0'); - break; - case VIDEO_PALETTE_UYVY: - fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'); - break; - case VIDEO_PALETTE_YUV411P: - fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B'); - break; - case VIDEO_PALETTE_YUV411: - fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P'); - break; - case VIDEO_PALETTE_YUV422P: - fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B'); - break; - case VIDEO_PALETTE_YUV410P: - fourcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9'); - break; - case VIDEO_PALETTE_RGB555: - case VIDEO_PALETTE_RGB565: - case VIDEO_PALETTE_RGB24: - case VIDEO_PALETTE_RGB32: - fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' '); - break; - default: - return NULL; - } - - if (fourcc == GST_MAKE_FOURCC ('R', 'G', 'B', ' ')) { - switch (palette) { - case VIDEO_PALETTE_RGB555: - caps = gst_caps_from_string ("video/x-raw-rgb, " - "bpp = (int) 16, " - "depth = (int) 15, " - "endianness = (int) BYTE_ORDER, " - "red_mask = 0x7c00, " "green_mask = 0x03e0, " "blue_mask = 0x001f"); - break; - case VIDEO_PALETTE_RGB565: - caps = gst_caps_from_string ("video/x-raw-rgb, " - "bpp = (int) 16, " - "depth = (int) 16, " - "endianness = (int) BYTE_ORDER, " - "red_mask = 0xf800, " "green_mask = 0x07f0, " "blue_mask = 0x001f"); - break; - case VIDEO_PALETTE_RGB24: - caps = gst_caps_from_string ("video/x-raw-rgb, " - "bpp = (int) 24, " - "depth = (int) 24, " - "endianness = (int) BIG_ENDIAN, " - "red_mask = 0xFF0000, " - "green_mask = 0x00FF00, " "blue_mask = 0x0000FF"); - break; - case VIDEO_PALETTE_RGB32: - caps = gst_caps_from_string ("video/x-raw-rgb, " - "bpp = (int) 32, " - "depth = (int) 24, " - "endianness = (int) BIG_ENDIAN, " - "red_mask = 0xFF000000, " - "green_mask = 0x00FF0000, " "blue_mask = 0x0000FF00"); - break; - default: - g_assert_not_reached (); - return NULL; - } - } else { - caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, fourcc, NULL); - } - - return caps; -} - -static GstCaps * -gst_v4lsrc_get_any_caps (void) -{ - gint i; - GstCaps *caps = gst_caps_new_empty (), *one; - - for (i = 0; all_palettes[i] != -1; i++) { - one = gst_v4lsrc_palette_to_caps (all_palettes[i]); - gst_caps_append (caps, one); - } - - return caps; -} - -static GstCaps * -gst_v4lsrc_get_caps (GstBaseSrc * src) -{ - GstCaps *list; - GstV4lSrc *v4lsrc = GST_V4LSRC (src); - struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap; - gint width = GST_V4LELEMENT (src)->vcap.minwidth; - gint height = GST_V4LELEMENT (src)->vcap.minheight; - gint i; - gint fps_n, fps_d; - GList *item; - - if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) { - return gst_v4lsrc_get_any_caps (); - } - - if (!v4lsrc->autoprobe) { - /* FIXME: query current caps and return those, with _any appended */ - return gst_v4lsrc_get_any_caps (); - } - - if (!v4lsrc->colorspaces) { - GST_DEBUG_OBJECT (v4lsrc, "Checking supported palettes"); - for (i = 0; all_palettes[i] != -1; i++) { - /* try palette out */ - if (!gst_v4lsrc_try_capture (v4lsrc, width, height, all_palettes[i])) - continue; - GST_DEBUG_OBJECT (v4lsrc, "Added palette %d (%s) to supported list", - all_palettes[i], gst_v4lsrc_palette_name (all_palettes[i])); - v4lsrc->colorspaces = g_list_append (v4lsrc->colorspaces, - GINT_TO_POINTER (all_palettes[i])); - } - GST_DEBUG_OBJECT (v4lsrc, "%d palette(s) supported", - g_list_length (v4lsrc->colorspaces)); - if (v4lsrc->autoprobe_fps) { - GST_DEBUG_OBJECT (v4lsrc, "autoprobing framerates"); - v4lsrc->fps_list = gst_v4lsrc_get_fps_list (v4lsrc); - } - } - - - if (!gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)) { - fps_n = 0; - fps_d = 1; - } - - list = gst_caps_new_empty (); - for (item = v4lsrc->colorspaces; item != NULL; item = item->next) { - GstCaps *one; - - one = gst_v4lsrc_palette_to_caps (GPOINTER_TO_INT (item->data)); - if (!one) { - GST_WARNING_OBJECT (v4lsrc, "Palette %d gave no caps\n", - GPOINTER_TO_INT (item->data)); - continue; - } - - GST_DEBUG_OBJECT (v4lsrc, - "Device reports w: %d-%d, h: %d-%d, fps: %d/%d for palette %d", - vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight, - fps_n, fps_d, GPOINTER_TO_INT (item->data)); - - if (vcap->minwidth < vcap->maxwidth) { - gst_caps_set_simple (one, "width", GST_TYPE_INT_RANGE, vcap->minwidth, - vcap->maxwidth, NULL); - } else { - gst_caps_set_simple (one, "width", G_TYPE_INT, vcap->minwidth, NULL); - } - if (vcap->minheight < vcap->maxheight) { - gst_caps_set_simple (one, "height", GST_TYPE_INT_RANGE, vcap->minheight, - vcap->maxheight, NULL); - } else { - gst_caps_set_simple (one, "height", G_TYPE_INT, vcap->minheight, NULL); - } - - if (v4lsrc->autoprobe_fps) { - GstStructure *structure = gst_caps_get_structure (one, 0); - - if (v4lsrc->fps_list) { - gst_structure_set_value (structure, "framerate", v4lsrc->fps_list); - } else { - gst_structure_set (structure, "framerate", GST_TYPE_FRACTION, - fps_n, fps_d, NULL); - } - } else { - gst_caps_set_simple (one, "framerate", GST_TYPE_FRACTION_RANGE, - 1, 1, 100, 1, NULL); - } - - GST_DEBUG_OBJECT (v4lsrc, "caps: %" GST_PTR_FORMAT, one); - gst_caps_append (list, one); - } - - return list; -} - -static gboolean -gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps) -{ - GstV4lSrc *v4lsrc; - guint32 fourcc; - gint bpp, depth, w, h, palette = -1; - const GValue *new_fps; - gint cur_fps_n, cur_fps_d; - GstStructure *structure; - struct video_window *vwin; - - v4lsrc = GST_V4LSRC (src); - vwin = &GST_V4LELEMENT (v4lsrc)->vwin; - - /* if we're not open, punt -- we'll get setcaps'd later via negotiate */ - if (!GST_V4L_IS_OPEN (v4lsrc)) - return FALSE; - - /* make sure we stop capturing and dealloc buffers */ - if (GST_V4L_IS_ACTIVE (v4lsrc)) { - if (!gst_v4lsrc_capture_stop (v4lsrc)) - return FALSE; - if (!gst_v4lsrc_capture_deinit (v4lsrc)) - return FALSE; - } - - /* it's fixed, one struct */ - structure = gst_caps_get_structure (caps, 0); - - if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0) - gst_structure_get_fourcc (structure, "format", &fourcc); - else - fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' '); - - gst_structure_get_int (structure, "width", &w); - gst_structure_get_int (structure, "height", &h); - new_fps = gst_structure_get_value (structure, "framerate"); - - /* set framerate if it's not already correct */ - if (!gst_v4lsrc_get_fps (v4lsrc, &cur_fps_n, &cur_fps_d)) - return FALSE; - - if (new_fps) { - GST_DEBUG_OBJECT (v4lsrc, "linking with %dx%d at %d/%d fps", w, h, - gst_value_get_fraction_numerator (new_fps), - gst_value_get_fraction_denominator (new_fps)); - - if (gst_value_get_fraction_numerator (new_fps) != cur_fps_n || - gst_value_get_fraction_denominator (new_fps) != cur_fps_d) { - int fps_index = (gst_value_get_fraction_numerator (new_fps) * 16) / - (gst_value_get_fraction_denominator (new_fps) * 15); - - GST_DEBUG_OBJECT (v4lsrc, "Trying to set fps index %d", fps_index); - /* set bits 16 to 21 to 0 */ - vwin->flags &= (0x3F00 - 1); - /* set bits 16 to 21 to the index */ - vwin->flags |= fps_index << 16; - if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) { - return FALSE; - } - } - } - - switch (fourcc) { - case GST_MAKE_FOURCC ('I', '4', '2', '0'): - palette = VIDEO_PALETTE_YUV420P; - v4lsrc->buffer_size = ((w + 1) & ~1) * ((h + 1) & ~1) * 1.5; - break; - case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): - palette = VIDEO_PALETTE_YUV422; - v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2; - break; - case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): - palette = VIDEO_PALETTE_UYVY; - v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2; - break; - case GST_MAKE_FOURCC ('Y', '4', '1', 'B'): - palette = VIDEO_PALETTE_YUV411P; - v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5; - break; - case GST_MAKE_FOURCC ('Y', '4', '1', 'P'): - palette = VIDEO_PALETTE_YUV411; - v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5; - break; - case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'): - palette = VIDEO_PALETTE_YUV410P; - v4lsrc->buffer_size = ((w + 3) & ~3) * ((h + 3) & ~3) * 1.125; - break; - case GST_MAKE_FOURCC ('Y', '4', '2', 'B'): - palette = VIDEO_PALETTE_YUV422P; - v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2; - break; - case GST_MAKE_FOURCC ('R', 'G', 'B', ' '): - gst_structure_get_int (structure, "depth", &depth); - switch (depth) { - case 15: - palette = VIDEO_PALETTE_RGB555; - v4lsrc->buffer_size = w * h * 2; - break; - case 16: - palette = VIDEO_PALETTE_RGB565; - v4lsrc->buffer_size = w * h * 2; - break; - case 24: - gst_structure_get_int (structure, "bpp", &bpp); - switch (bpp) { - case 24: - palette = VIDEO_PALETTE_RGB24; - v4lsrc->buffer_size = w * h * 3; - break; - case 32: - palette = VIDEO_PALETTE_RGB32; - v4lsrc->buffer_size = w * h * 4; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - - if (palette == -1) { - GST_WARNING_OBJECT (v4lsrc, "palette for fourcc %" GST_FOURCC_FORMAT - " is -1, refusing link", GST_FOURCC_ARGS (fourcc)); - return FALSE; - } - - GST_DEBUG_OBJECT (v4lsrc, "trying to set_capture %dx%d, palette %d", - w, h, palette); - /* this only fills in v4lsrc->mmap values */ - if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) { - GST_WARNING_OBJECT (v4lsrc, "could not set_capture %dx%d, palette %d", - w, h, palette); - return FALSE; - } - - /* first try the negotiated settings using try_capture */ - if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) { - GST_DEBUG_OBJECT (v4lsrc, "failed trying palette %d for %dx%d", palette, - w, h); - return FALSE; - } - - if (!gst_v4lsrc_capture_init (v4lsrc)) - return FALSE; - - if (!gst_v4lsrc_capture_start (v4lsrc)) - return FALSE; - - return TRUE; -} - -static gboolean -gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query) -{ - GstV4lSrc *v4lsrc; - gboolean res = FALSE; - - v4lsrc = GST_V4LSRC (bsrc); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_LATENCY: - { - GstClockTime min_latency, max_latency; - gint fps_n, fps_d; - - /* device must be open */ - if (!GST_V4L_IS_OPEN (v4lsrc)) - goto done; - - /* we must have a framerate */ - if (!(res = gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d))) - goto done; - - /* min latency is the time to capture one frame */ - min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n); - - /* max latency is total duration of the frame buffer */ - max_latency = v4lsrc->mbuf.frames * min_latency; - - GST_DEBUG_OBJECT (bsrc, - "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); - - /* we are always live, the min latency is 1 frame and the max latency is - * the complete buffer of frames. */ - gst_query_set_latency (query, TRUE, min_latency, max_latency); - - res = TRUE; - break; - } - default: - res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query); - break; - } -done: - return res; -} - -/* start and stop are not symmetric -- start will open the device, but not start - capture. it's setcaps that will start capture, which is called via basesrc's - negotiate method. stop will both stop capture and close the device. - */ -static gboolean -gst_v4lsrc_start (GstBaseSrc * src) -{ - GstV4lSrc *v4lsrc = GST_V4LSRC (src); - - if (!GST_BASE_SRC_CLASS (parent_class)->start (src)) - return FALSE; - - v4lsrc->offset = 0; - - return TRUE; -} - -static gboolean -gst_v4lsrc_stop (GstBaseSrc * src) -{ - GstV4lSrc *v4lsrc = GST_V4LSRC (src); - - if (GST_V4L_IS_ACTIVE (v4lsrc) && !gst_v4lsrc_capture_stop (v4lsrc)) - return FALSE; - - if (GST_V4LELEMENT (v4lsrc)->buffer != NULL) { - if (!gst_v4lsrc_capture_deinit (v4lsrc)) - return FALSE; - } - - if (!GST_BASE_SRC_CLASS (parent_class)->stop (src)) - return FALSE; - - g_list_free (v4lsrc->colorspaces); - v4lsrc->colorspaces = NULL; - - if (v4lsrc->fps_list) { - g_value_unset (v4lsrc->fps_list); - g_free (v4lsrc->fps_list); - v4lsrc->fps_list = NULL; - } - - return TRUE; -} - -static GstFlowReturn -gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** buf) -{ - GstV4lSrc *v4lsrc; - gint num; - - v4lsrc = GST_V4LSRC (src); - - /* grab a frame from the device */ - if (!gst_v4lsrc_grab_frame (v4lsrc, &num)) - return GST_FLOW_ERROR; - - *buf = gst_v4lsrc_buffer_new (v4lsrc, num); - - if (v4lsrc->copy_mode) { - GstBuffer *copy = gst_buffer_copy (*buf); - - gst_buffer_unref (*buf); - *buf = copy; - } - - return GST_FLOW_OK; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4lsrc.h --- a/gst_plugins_base/sys/v4l/gstv4lsrc.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* GStreamer - * - * gstv4lsrc.h: BT8x8/V4L video source element - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifndef __GST_V4LSRC_H__ -#define __GST_V4LSRC_H__ - - -#include - - -G_BEGIN_DECLS - - -#define GST_TYPE_V4LSRC \ - (gst_v4lsrc_get_type()) -#define GST_V4LSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LSRC,GstV4lSrc)) -#define GST_V4LSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LSRC,GstV4lSrcClass)) -#define GST_IS_V4LSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LSRC)) -#define GST_IS_V4LSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LSRC)) - - -typedef struct _GstV4lSrc GstV4lSrc; -typedef struct _GstV4lSrcClass GstV4lSrcClass; - - -enum -{ - QUEUE_STATE_ERROR = -1, - QUEUE_STATE_READY_FOR_QUEUE, /* the frame is ready to be queued for capture */ - QUEUE_STATE_QUEUED, /* the frame is queued for capture */ - QUEUE_STATE_SYNCED /* the frame is captured */ -}; - - -struct _GstV4lSrc -{ - GstV4lElement v4lelement; - - /* pads */ - GstPad *srcpad; - - /* capture/buffer info */ - struct video_mmap mmap; - struct video_mbuf mbuf; - guint buffer_size; - GstClockTime timestamp_sync; - - /* num of queued frames and some GThread stuff - * to wait if there's not enough */ - gint8 *frame_queue_state; - GMutex *mutex_queue_state; - GCond *cond_queue_state; - gint num_queued; - gint sync_frame, queue_frame; - gboolean is_capturing; - GstClockTimeDiff timestamp_offset; - - /* True if we want to stop */ - gboolean quit; - - gint offset; - - /* list of supported colorspaces (as integers) */ - GList *colorspaces; - - gboolean autoprobe; /* probe features on startup ? */ - gboolean autoprobe_fps; /* probe fps on startup ? */ - gboolean copy_mode; - - GValue *fps_list; /* list of fps probed */ -}; - -struct _GstV4lSrcClass -{ - GstV4lElementClass parent_class; -}; - - -GType gst_v4lsrc_get_type (void); - - -G_END_DECLS - - -#endif /* __GST_V4LSRC_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4ltuner.c --- a/gst_plugins_base/sys/v4l/gstv4ltuner.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,328 +0,0 @@ -/* GStreamer - * - * gstv4ltuner.c: tuner interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "gstv4ltuner.h" -#include "gstv4lelement.h" -#include "v4l_calls.h" - -static void gst_v4l_tuner_channel_class_init (GstV4lTunerChannelClass * klass); -static void gst_v4l_tuner_channel_init (GstV4lTunerChannel * channel); - -static void gst_v4l_tuner_norm_class_init (GstV4lTunerNormClass * klass); -static void gst_v4l_tuner_norm_init (GstV4lTunerNorm * norm); - -static const GList *gst_v4l_tuner_list_channels (GstTuner * tuner); -static void gst_v4l_tuner_set_channel (GstTuner * tuner, - GstTunerChannel * channel); -static GstTunerChannel *gst_v4l_tuner_get_channel (GstTuner * tuner); - -static const GList *gst_v4l_tuner_list_norms (GstTuner * tuner); -static void gst_v4l_tuner_set_norm (GstTuner * tuner, GstTunerNorm * norm); -static GstTunerNorm *gst_v4l_tuner_get_norm (GstTuner * tuner); - -static void gst_v4l_tuner_set_frequency (GstTuner * tuner, - GstTunerChannel * channel, gulong frequency); -static gulong gst_v4l_tuner_get_frequency (GstTuner * tuner, - GstTunerChannel * channel); -static gint gst_v4l_tuner_signal_strength (GstTuner * tuner, - GstTunerChannel * channel); - -static GstTunerNormClass *norm_parent_class = NULL; -static GstTunerChannelClass *channel_parent_class = NULL; - -GType -gst_v4l_tuner_channel_get_type (void) -{ - static GType gst_v4l_tuner_channel_type = 0; - - if (!gst_v4l_tuner_channel_type) { - static const GTypeInfo v4l_tuner_channel_info = { - sizeof (GstV4lTunerChannelClass), - NULL, - NULL, - (GClassInitFunc) gst_v4l_tuner_channel_class_init, - NULL, - NULL, - sizeof (GstV4lTunerChannel), - 0, - (GInstanceInitFunc) gst_v4l_tuner_channel_init, - NULL - }; - - gst_v4l_tuner_channel_type = - g_type_register_static (GST_TYPE_TUNER_CHANNEL, - "GstV4lTunerChannel", &v4l_tuner_channel_info, 0); - } - - return gst_v4l_tuner_channel_type; -} - -static void -gst_v4l_tuner_channel_class_init (GstV4lTunerChannelClass * klass) -{ - channel_parent_class = g_type_class_peek_parent (klass); -} - -static void -gst_v4l_tuner_channel_init (GstV4lTunerChannel * channel) -{ - channel->index = 0; - channel->audio = 0; - channel->tuner = 0; -} - -GType -gst_v4l_tuner_norm_get_type (void) -{ - static GType gst_v4l_tuner_norm_type = 0; - - if (!gst_v4l_tuner_norm_type) { - static const GTypeInfo v4l_tuner_norm_info = { - sizeof (GstV4lTunerNormClass), - NULL, - NULL, - (GClassInitFunc) gst_v4l_tuner_norm_class_init, - NULL, - NULL, - sizeof (GstV4lTunerNorm), - 0, - (GInstanceInitFunc) gst_v4l_tuner_norm_init, - NULL - }; - - gst_v4l_tuner_norm_type = - g_type_register_static (GST_TYPE_TUNER_NORM, - "GstV4lTunerNorm", &v4l_tuner_norm_info, 0); - } - - return gst_v4l_tuner_norm_type; -} - -static void -gst_v4l_tuner_norm_class_init (GstV4lTunerNormClass * klass) -{ - norm_parent_class = g_type_class_peek_parent (klass); -} - -static void -gst_v4l_tuner_norm_init (GstV4lTunerNorm * norm) -{ - norm->index = 0; -} - -void -gst_v4l_tuner_interface_init (GstTunerClass * klass) -{ - /* default virtual functions */ - klass->list_channels = gst_v4l_tuner_list_channels; - klass->set_channel = gst_v4l_tuner_set_channel; - klass->get_channel = gst_v4l_tuner_get_channel; - - klass->list_norms = gst_v4l_tuner_list_norms; - klass->set_norm = gst_v4l_tuner_set_norm; - klass->get_norm = gst_v4l_tuner_get_norm; - - klass->set_frequency = gst_v4l_tuner_set_frequency; - klass->get_frequency = gst_v4l_tuner_get_frequency; - klass->signal_strength = gst_v4l_tuner_signal_strength; -} - -static G_GNUC_UNUSED gboolean -gst_v4l_tuner_contains_channel (GstV4lElement * v4lelement, - GstV4lTunerChannel * v4lchannel) -{ - const GList *item; - - for (item = v4lelement->channels; item != NULL; item = item->next) - if (item->data == v4lchannel) - return TRUE; - - return FALSE; -} - -static const GList * -gst_v4l_tuner_list_channels (GstTuner * tuner) -{ - return GST_V4LELEMENT (tuner)->channels; -} - -static void -gst_v4l_tuner_set_channel (GstTuner * tuner, GstTunerChannel * channel) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); - gint norm; - - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); - g_return_if_fail (gst_v4l_tuner_contains_channel (v4lelement, v4lchannel)); - - gst_v4l_get_chan_norm (v4lelement, NULL, &norm); - gst_v4l_set_chan_norm (v4lelement, v4lchannel->index, norm); -} - -static GstTunerChannel * -gst_v4l_tuner_get_channel (GstTuner * tuner) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GList *item; - gint channel; - - /* assert that we're opened */ - g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), NULL); - - gst_v4l_get_chan_norm (v4lelement, &channel, NULL); - - for (item = v4lelement->channels; item != NULL; item = item->next) { - if (channel == GST_V4L_TUNER_CHANNEL (item->data)->index) - return GST_TUNER_CHANNEL (item->data); - } - - return NULL; -} - -static G_GNUC_UNUSED gboolean -gst_v4l_tuner_contains_norm (GstV4lElement * v4lelement, - GstV4lTunerNorm * v4lnorm) -{ - const GList *item; - - for (item = v4lelement->norms; item != NULL; item = item->next) - if (item->data == v4lnorm) - return TRUE; - - return FALSE; -} - -static const GList * -gst_v4l_tuner_list_norms (GstTuner * tuner) -{ - return GST_V4LELEMENT (tuner)->norms; -} - -static void -gst_v4l_tuner_set_norm (GstTuner * tuner, GstTunerNorm * norm) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GstV4lTunerNorm *v4lnorm = GST_V4L_TUNER_NORM (norm); - gint channel; - - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); - g_return_if_fail (gst_v4l_tuner_contains_norm (v4lelement, v4lnorm)); - - gst_v4l_get_chan_norm (v4lelement, &channel, NULL); - gst_v4l_set_chan_norm (v4lelement, channel, v4lnorm->index); -} - -static GstTunerNorm * -gst_v4l_tuner_get_norm (GstTuner * tuner) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GList *item; - gint norm; - - /* assert that we're opened */ - g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), NULL); - - gst_v4l_get_chan_norm (v4lelement, NULL, &norm); - - for (item = v4lelement->norms; item != NULL; item = item->next) { - if (norm == GST_V4L_TUNER_NORM (item->data)->index) - return GST_TUNER_NORM (item->data); - } - - return NULL; -} - -static void -gst_v4l_tuner_set_frequency (GstTuner * tuner, - GstTunerChannel * channel, gulong frequency) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); - gint chan; - - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); - g_return_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, - GST_TUNER_CHANNEL_FREQUENCY)); - g_return_if_fail (gst_v4l_tuner_contains_channel (v4lelement, v4lchannel)); - - gst_v4l_get_chan_norm (v4lelement, &chan, NULL); - if (chan == GST_V4L_TUNER_CHANNEL (channel)->index) { - gst_v4l_set_frequency (v4lelement, v4lchannel->tuner, frequency); - } -} - -static gulong -gst_v4l_tuner_get_frequency (GstTuner * tuner, GstTunerChannel * channel) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); - gint chan; - gulong frequency = 0; - - /* assert that we're opened and that we're using a known item */ - g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), 0); - g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, - GST_TUNER_CHANNEL_FREQUENCY), 0); - g_return_val_if_fail (gst_v4l_tuner_contains_channel (v4lelement, - v4lchannel), 0); - - gst_v4l_get_chan_norm (v4lelement, &chan, NULL); - if (chan == GST_V4L_TUNER_CHANNEL (channel)->index) { - gst_v4l_get_frequency (v4lelement, v4lchannel->tuner, &frequency); - } - - return frequency; -} - -static gint -gst_v4l_tuner_signal_strength (GstTuner * tuner, GstTunerChannel * channel) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); - gint chan; - guint signal = 0; - - /* assert that we're opened and that we're using a known item */ - g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), 0); - g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, - GST_TUNER_CHANNEL_FREQUENCY), 0); - g_return_val_if_fail (gst_v4l_tuner_contains_channel (v4lelement, - v4lchannel), 0); - - gst_v4l_get_chan_norm (v4lelement, &chan, NULL); - if (chan == GST_V4L_TUNER_CHANNEL (channel)->index && - GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { - gst_v4l_get_signal (v4lelement, v4lchannel->tuner, &signal); - } - - return (gint) signal; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4ltuner.h --- a/gst_plugins_base/sys/v4l/gstv4ltuner.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* GStreamer - * - * gstv4ltuner.h: tuner interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje - * - * 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. - */ - -#ifndef __GST_V4L_TUNER_H__ -#define __GST_V4L_TUNER_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_V4L_TUNER_CHANNEL \ - (gst_v4l_tuner_channel_get_type ()) -#define GST_V4L_TUNER_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L_TUNER_CHANNEL, \ - GstV4lTunerChannel)) -#define GST_V4L_TUNER_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L_TUNER_CHANNEL, \ - GstV4lTunerChannelClass)) -#define GST_IS_V4L_TUNER_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L_TUNER_CHANNEL)) -#define GST_IS_V4L_TUNER_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L_TUNER_CHANNEL)) - -typedef struct _GstV4lTunerChannel { - GstTunerChannel parent; - - gint index; - gint tuner; - gint audio; -} GstV4lTunerChannel; - -typedef struct _GstV4lTunerChannelClass { - GstTunerChannelClass parent; -} GstV4lTunerChannelClass; - -#define GST_TYPE_V4L_TUNER_NORM \ - (gst_v4l_tuner_norm_get_type ()) -#define GST_V4L_TUNER_NORM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L_TUNER_NORM, \ - GstV4lTunerNorm)) -#define GST_V4L_TUNER_NORM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L_TUNER_NORM, \ - GstV4lTunerNormClass)) -#define GST_IS_V4L_TUNER_NORM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L_TUNER_NORM)) -#define GST_IS_V4L_TUNER_NORM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L_TUNER_NORM)) - -typedef struct _GstV4lTunerNorm { - GstTunerNorm parent; - - gint index; -} GstV4lTunerNorm; - -typedef struct _GstV4lTunerNormClass { - GstTunerNormClass parent; -} GstV4lTunerNormClass; - -GType gst_v4l_tuner_channel_get_type (void); -GType gst_v4l_tuner_norm_get_type (void); - -void gst_v4l_tuner_interface_init (GstTunerClass *klass); - -#endif /* __GST_V4L_TUNER_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4lxoverlay.c --- a/gst_plugins_base/sys/v4l/gstv4lxoverlay.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,245 +0,0 @@ -/* GStreamer - * - * gstv4lxoverlay.c: X-based overlay interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include -#include -#include -#include - -#include "gstv4lxoverlay.h" -#include "gstv4lelement.h" -#include "v4l_calls.h" - -GST_DEBUG_CATEGORY_STATIC (v4lxv_debug); -#define GST_CAT_DEFAULT v4lxv_debug - -struct _GstV4lXv -{ - Display *dpy; - gint port, idle_id; - GMutex *mutex; -}; - -static void gst_v4l_xoverlay_set_xwindow_id (GstXOverlay * overlay, - XID xwindow_id); - -void -gst_v4l_xoverlay_interface_init (GstXOverlayClass * klass) -{ - /* default virtual functions */ - klass->set_xwindow_id = gst_v4l_xoverlay_set_xwindow_id; - - GST_DEBUG_CATEGORY_INIT (v4lxv_debug, "v4lxv", 0, - "V4L XOverlay interface debugging"); -} - -static void -gst_v4l_xoverlay_open (GstV4lElement * v4lelement) -{ - struct stat s; - GstV4lXv *v4lxv; - const gchar *name = g_getenv ("DISPLAY"); - unsigned int ver, rel, req, ev, err, anum; - int i, id = 0, first_id = 0, min; - XvAdaptorInfo *ai; - Display *dpy; - - /* we need a display, obviously */ - if (!name || !(dpy = XOpenDisplay (name))) { - GST_WARNING ("No $DISPLAY set or failed to open - no overlay"); - return; - } - - /* First let's check that XVideo extension is available */ - if (!XQueryExtension (dpy, "XVideo", &i, &i, &i)) { - GST_WARNING ("Xv extension not available - no overlay"); - XCloseDisplay (dpy); - return; - } - - /* find port that belongs to this device */ - if (XvQueryExtension (dpy, &ver, &rel, &req, &ev, &err) != Success) { - GST_WARNING ("Xv extension not supported - no overlay"); - XCloseDisplay (dpy); - return; - } - if (XvQueryAdaptors (dpy, DefaultRootWindow (dpy), &anum, &ai) != Success) { - GST_WARNING ("Failed to query Xv adaptors"); - XCloseDisplay (dpy); - return; - } - if (fstat (v4lelement->video_fd, &s) < 0) { - GST_ERROR ("Failed to stat() file descriptor: %s", g_strerror (errno)); - XCloseDisplay (dpy); - return; - } - min = s.st_rdev & 0xff; - for (i = 0; i < anum; i++) { - if (!strcmp (ai[i].name, "video4linux")) { - if (first_id == 0) - first_id = ai[i].base_id; - - /* hmm... */ - if (first_id != 0 && ai[i].base_id == first_id + min) - id = ai[i].base_id; - } - } - XvFreeAdaptorInfo (ai); - - if (id == 0) { - GST_WARNING ("Did not find XvPortID for device - no overlay"); - XCloseDisplay (dpy); - return; - } - - v4lxv = g_new0 (GstV4lXv, 1); - v4lxv->dpy = dpy; - v4lxv->port = id; - v4lxv->mutex = g_mutex_new (); - v4lxv->idle_id = 0; - v4lelement->xv = v4lxv; - - if (v4lelement->xwindow_id) { - gst_v4l_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4lelement), - v4lelement->xwindow_id); - } -} - -static void -gst_v4l_xoverlay_close (GstV4lElement * v4lelement) -{ - GstV4lXv *v4lxv = v4lelement->xv; - - if (!v4lelement->xv) - return; - - if (v4lelement->xwindow_id) { - gst_v4l_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4lelement), 0); - } - - XCloseDisplay (v4lxv->dpy); - g_mutex_free (v4lxv->mutex); - if (v4lxv->idle_id) - g_source_remove (v4lxv->idle_id); - g_free (v4lxv); - v4lelement->xv = NULL; -} - -void -gst_v4l_xoverlay_start (GstV4lElement * v4lelement) -{ - if (v4lelement->xwindow_id) { - gst_v4l_xoverlay_open (v4lelement); - } -} - -void -gst_v4l_xoverlay_stop (GstV4lElement * v4lelement) -{ - gst_v4l_xoverlay_close (v4lelement); -} - -static gboolean -idle_refresh (gpointer data) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (data); - GstV4lXv *v4lxv = v4lelement->xv; - XWindowAttributes attr; - - if (v4lxv) { - g_mutex_lock (v4lxv->mutex); - - XGetWindowAttributes (v4lxv->dpy, v4lelement->xwindow_id, &attr); - XvPutVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id, - DefaultGC (v4lxv->dpy, DefaultScreen (v4lxv->dpy)), - 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); - - v4lxv->idle_id = 0; - g_mutex_unlock (v4lxv->mutex); - } - - /* once */ - return FALSE; -} - -static void -gst_v4l_xoverlay_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (overlay); - GstV4lXv *v4lxv; - XWindowAttributes attr; - gboolean change = (v4lelement->xwindow_id != xwindow_id); - - GST_LOG_OBJECT (v4lelement, "Changing port to %lx", xwindow_id); - - if (!v4lelement->xv && GST_V4L_IS_OPEN (v4lelement)) - gst_v4l_xoverlay_open (v4lelement); - - v4lxv = v4lelement->xv; - - if (v4lxv) - g_mutex_lock (v4lxv->mutex); - - if (change) { - if (v4lelement->xwindow_id && v4lxv) { - GST_DEBUG_OBJECT (v4lelement, - "Disabling port %lx", v4lelement->xwindow_id); - - XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 0); - XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 0); - XvStopVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id); - } - - v4lelement->xwindow_id = xwindow_id; - } - - if (!v4lxv || xwindow_id == 0) { - if (v4lxv) - g_mutex_unlock (v4lxv->mutex); - return; - } - - if (change) { - GST_DEBUG_OBJECT (v4lelement, "Enabling port %lx", xwindow_id); - - /* draw */ - XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 1); - XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 1); - } - - XGetWindowAttributes (v4lxv->dpy, v4lelement->xwindow_id, &attr); - XvPutVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id, - DefaultGC (v4lxv->dpy, DefaultScreen (v4lxv->dpy)), - 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); - - if (v4lxv->idle_id) - g_source_remove (v4lxv->idle_id); - v4lxv->idle_id = g_idle_add (idle_refresh, v4lelement); - g_mutex_unlock (v4lxv->mutex); -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/gstv4lxoverlay.h --- a/gst_plugins_base/sys/v4l/gstv4lxoverlay.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* GStreamer - * - * gstv4lxoverlay.h: tv mixer interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje - * - * 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. - */ - -#ifndef __GST_V4L_X_OVERLAY_H__ -#define __GST_V4L_X_OVERLAY_H__ - -#include -#include - -#include "gstv4lelement.h" - -G_BEGIN_DECLS - -void gst_v4l_xoverlay_interface_init (GstXOverlayClass *klass); - -void gst_v4l_xoverlay_start (GstV4lElement * v4lelement); -void gst_v4l_xoverlay_stop (GstV4lElement * v4lelement); - -G_END_DECLS - -#endif /* __GST_V4L_X_OVERLAY_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/v4l_calls.c --- a/gst_plugins_base/sys/v4l/v4l_calls.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,723 +0,0 @@ -/* GStreamer - * - * v4l_calls.c: generic V4L calls - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "v4l_calls.h" -#include "gstv4ltuner.h" -#include "gstv4lcolorbalance.h" - -#include "gstv4lsrc.h" -/* #include "gstv4lmjpegsrc.h" */ -/* #include "gstv4lmjpegsink.h" */ - -GST_DEBUG_CATEGORY_EXTERN (v4l_debug); -#define GST_CAT_DEFAULT v4l_debug - -static const char *picture_name[] = { - "Hue", - "Brightness", - "Contrast", - "Saturation", - NULL -}; - -G_GNUC_UNUSED static const char *audio_name[] = { - "Volume", - "Mute", - "Mode", - NULL -}; - -static const char *norm_name[] = { - "PAL", - "NTSC", - "SECAM", - NULL -}; - -/****************************************************** - * gst_v4l_get_capabilities(): - * get the device's capturing capabilities - * sets v4lelement->vcap and v4lelement->vwin - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_capabilities (GstV4lElement * v4lelement) -{ - GST_DEBUG_OBJECT (v4lelement, "getting capabilities"); - GST_V4L_CHECK_OPEN (v4lelement); - - if (ioctl (v4lelement->video_fd, VIDIOCGCAP, &(v4lelement->vcap)) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("error getting capabilities %s of from device %s", - g_strerror (errno), v4lelement->videodev)); - return FALSE; - } - - if (ioctl (v4lelement->video_fd, VIDIOCGWIN, &(v4lelement->vwin)) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("error getting window properties %s of from device %s", - g_strerror (errno), v4lelement->videodev)); - return FALSE; - } - - return TRUE; -} - -/****************************************************** - * gst_v4l_set_window_properties(): - * set the device's capturing parameters (vwin) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_window_properties (GstV4lElement * v4lelement) -{ - struct video_window vwin; - - GST_DEBUG_OBJECT (v4lelement, "setting window flags 0x%x to device %s", - v4lelement->vwin.flags, v4lelement->videodev); - GST_V4L_CHECK_OPEN (v4lelement); - - if (ioctl (v4lelement->video_fd, VIDIOCSWIN, &(v4lelement->vwin)) < 0) { - GST_DEBUG_OBJECT (v4lelement, - "could not ioctl window properties 0x%x to device %s", - v4lelement->vwin.flags, v4lelement->videodev); - return FALSE; - } - - /* get it again to make sure we have it correctly */ - if (ioctl (v4lelement->video_fd, VIDIOCGWIN, &(vwin)) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("error getting window properties %s of from device %s", - g_strerror (errno), v4lelement->videodev)); - return FALSE; - } - if (vwin.flags != v4lelement->vwin.flags) { - GST_DEBUG_OBJECT (v4lelement, "set 0x%x but got 0x%x back", - v4lelement->vwin.flags, vwin.flags); - return FALSE; - } - - return TRUE; -} - -/****************************************************** - * gst_v4l_open(): - * open the video device (v4lelement->videodev) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_open (GstV4lElement * v4lelement) -{ - int num; - - GST_DEBUG_OBJECT (v4lelement, "opening device %s", v4lelement->videodev); - GST_V4L_CHECK_NOT_OPEN (v4lelement); - GST_V4L_CHECK_NOT_ACTIVE (v4lelement); - - /* be sure we have a device */ - if (!v4lelement->videodev) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, NOT_FOUND, - (_("No device specified.")), (NULL)); - return FALSE; - } - - /* open the device */ - v4lelement->video_fd = open (v4lelement->videodev, O_RDWR); - if (!GST_V4L_IS_OPEN (v4lelement)) { - if (errno == ENODEV || errno == ENOENT) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, NOT_FOUND, - (_("Device \"%s\" does not exist."), v4lelement->videodev), (NULL)); - return FALSE; - } - if (errno == EBUSY) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, BUSY, - (_("Device \"%s\" is already being used."), v4lelement->videodev), - (NULL)); - return FALSE; - } - GST_ELEMENT_ERROR (v4lelement, RESOURCE, OPEN_READ_WRITE, - (_("Could not open device \"%s\" for reading and writing."), - v4lelement->videodev), GST_ERROR_SYSTEM); - return FALSE; - } - - /* get capabilities */ - if (!gst_v4l_get_capabilities (v4lelement)) { - close (v4lelement->video_fd); - v4lelement->video_fd = -1; - return FALSE; - } - - /* device type check */ - if ((GST_IS_V4LSRC (v4lelement) && - !(v4lelement->vcap.type & VID_TYPE_CAPTURE))) { -/* (GST_IS_V4LMJPEGSRC (v4lelement) && */ -/* !(v4lelement->vcap.type & VID_TYPE_MJPEG_ENCODER)) || */ -/* (GST_IS_V4LMJPEGSINK (v4lelement) && */ -/* !(v4lelement->vcap.type & VID_TYPE_MJPEG_DECODER))) { */ - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Device opened, but wrong type (0x%x)", v4lelement->vcap.type)); - close (v4lelement->video_fd); - v4lelement->video_fd = -1; - return FALSE; - } - - GST_INFO_OBJECT (v4lelement, "Opened device \'%s\' (\'%s\') successfully", - v4lelement->vcap.name, v4lelement->videodev); - - /* norms + inputs, for the tuner interface */ - for (num = 0; norm_name[num] != NULL; num++) { - GstV4lTunerNorm *v4lnorm = g_object_new (GST_TYPE_V4L_TUNER_NORM, - NULL); - GstTunerNorm *norm = GST_TUNER_NORM (v4lnorm); - - norm->label = g_strdup (norm_name[num]); - if (num == 1) - gst_value_set_fraction (&norm->framerate, 30000, 1001); - else - gst_value_set_fraction (&norm->framerate, 25, 1); - - v4lnorm->index = num; - v4lelement->norms = g_list_append (v4lelement->norms, (gpointer) norm); - } - v4lelement->channels = gst_v4l_get_chan_names (v4lelement); - - for (num = 0; picture_name[num] != NULL; num++) { - GstV4lColorBalanceChannel *v4lchannel = - g_object_new (GST_TYPE_V4L_COLOR_BALANCE_CHANNEL, NULL); - GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL (v4lchannel); - - channel->label = g_strdup (picture_name[num]); - channel->min_value = 0; - channel->max_value = 65535; - v4lchannel->index = num; - v4lelement->colors = g_list_append (v4lelement->colors, channel); - } - - GST_DEBUG_OBJECT (v4lelement, "Setting default norm/input"); - gst_v4l_set_chan_norm (v4lelement, 0, 0); - - return TRUE; -} - - -/****************************************************** - * gst_v4l_close(): - * close the video device (v4lelement->video_fd) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_close (GstV4lElement * v4lelement) -{ - GST_DEBUG_OBJECT (v4lelement, "closing device"); - GST_V4L_CHECK_OPEN (v4lelement); - GST_V4L_CHECK_NOT_ACTIVE (v4lelement); - - close (v4lelement->video_fd); - v4lelement->video_fd = -1; - - g_list_foreach (v4lelement->channels, (GFunc) g_object_unref, NULL); - g_list_free (v4lelement->channels); - v4lelement->channels = NULL; - - g_list_foreach (v4lelement->norms, (GFunc) g_object_unref, NULL); - g_list_free (v4lelement->norms); - v4lelement->norms = NULL; - - g_list_foreach (v4lelement->colors, (GFunc) g_object_unref, NULL); - g_list_free (v4lelement->colors); - v4lelement->colors = NULL; - - return TRUE; -} - - -/****************************************************** - * gst_v4l_get_num_chans() - * return value: the number of video input channels - ******************************************************/ - -static gint -gst_v4l_get_num_chans (GstV4lElement * v4lelement) -{ - GST_DEBUG_OBJECT (v4lelement, "getting number of channels"); - GST_V4L_CHECK_OPEN (v4lelement); - - return v4lelement->vcap.channels; -} - - -/****************************************************** - * gst_v4l_get_chan_names() - * return value: a GList containing the channel names - ******************************************************/ - -GList * -gst_v4l_get_chan_names (GstV4lElement * v4lelement) -{ - struct video_channel vchan; - GList *list = NULL; - gint i; - - GST_DEBUG_OBJECT (v4lelement, "getting channel names"); - - if (!GST_V4L_IS_OPEN (v4lelement)) - return NULL; - - for (i = 0; i < gst_v4l_get_num_chans (v4lelement); i++) { - GstV4lTunerChannel *v4lchannel = g_object_new (GST_TYPE_V4L_TUNER_CHANNEL, - NULL); - GstTunerChannel *channel = GST_TUNER_CHANNEL (v4lchannel); - - vchan.channel = i; - if (ioctl (v4lelement->video_fd, VIDIOCGCHAN, &vchan) < 0) - return NULL; /* memleak... */ - channel->label = g_strdup (vchan.name); - channel->flags = GST_TUNER_CHANNEL_INPUT; - v4lchannel->index = i; - if (vchan.flags & VIDEO_VC_TUNER) { - struct video_tuner vtun; - gint n; - - for (n = 0;; n++) { - if (n >= vchan.tuners) { - vtun.tuner = 0; /* default */ - } else { - vtun.tuner = n; - if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &vtun) < 0) - continue; /* no more tuners */ - if (strcmp (vtun.name, vchan.name) != 0) { - continue; /* not this one */ - } - } - v4lchannel->tuner = n; - channel->flags |= GST_TUNER_CHANNEL_FREQUENCY; - channel->freq_multiplicator = - 62.5 * ((vtun.flags & VIDEO_TUNER_LOW) ? 1 : 1000); - channel->min_frequency = vtun.rangelow; - channel->max_frequency = vtun.rangehigh; - channel->min_signal = 0; - channel->max_signal = 0xffff; - break; - } - - } - if (vchan.flags & VIDEO_VC_AUDIO) { - struct video_audio vaud; - gint n; - - for (n = 0; n < v4lelement->vcap.audios; n++) { - vaud.audio = n; - if (ioctl (v4lelement->video_fd, VIDIOCGAUDIO, &vaud) < 0) - continue; - if (!strcmp (vaud.name, vchan.name)) { - v4lchannel->audio = n; - channel->flags |= GST_TUNER_CHANNEL_AUDIO; - break; - } - } - } - list = g_list_append (list, (gpointer) channel); - } - - return list; -} - - -/****************************************************** - * gst_v4l_get_chan_norm(): - * get the currently active video-channel and it's - * norm (VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_chan_norm (GstV4lElement * v4lelement, gint * channel, gint * norm) -{ - GST_DEBUG_OBJECT (v4lelement, "getting current channel and norm"); - GST_V4L_CHECK_OPEN (v4lelement); - - if (channel) - *channel = v4lelement->vchan.channel; - if (norm) - *norm = v4lelement->vchan.norm; - - return TRUE; -} - - -/****************************************************** - * gst_v4l_set_chan_norm(): - * set a new active channel and it's norm - * (VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_chan_norm (GstV4lElement * v4lelement, gint channel, gint norm) -{ - GST_DEBUG_OBJECT (v4lelement, "setting channel = %d, norm = %d (%s)", - channel, norm, norm_name[norm]); - GST_V4L_CHECK_OPEN (v4lelement); - //GST_V4L_CHECK_NOT_ACTIVE (v4lelement); - - v4lelement->vchan.channel = channel; - v4lelement->vchan.norm = norm; - - if (ioctl (v4lelement->video_fd, VIDIOCSCHAN, &(v4lelement->vchan)) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting the channel/norm settings: %s", g_strerror (errno))); - return FALSE; - } - - if (ioctl (v4lelement->video_fd, VIDIOCGCHAN, &(v4lelement->vchan)) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting the channel/norm settings: %s", g_strerror (errno))); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_get_signal(): - * get the current signal - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_signal (GstV4lElement * v4lelement, gint tunernum, guint * signal) -{ - struct video_tuner tuner; - - GST_DEBUG_OBJECT (v4lelement, "getting tuner signal"); - GST_V4L_CHECK_OPEN (v4lelement); - - tuner.tuner = tunernum; - if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &tuner) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting tuner signal: %s", g_strerror (errno))); - return FALSE; - } - - *signal = tuner.signal; - - return TRUE; -} - - -/****************************************************** - * gst_v4l_get_frequency(): - * get the current frequency - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_frequency (GstV4lElement * v4lelement, - gint tunernum, gulong * frequency) -{ - struct video_tuner vtun; - GstTunerChannel *channel; - - GST_DEBUG_OBJECT (v4lelement, "getting tuner frequency"); - GST_V4L_CHECK_OPEN (v4lelement); - - channel = gst_tuner_get_channel (GST_TUNER (v4lelement)); - - /* check that this is the current input */ - vtun.tuner = tunernum; - if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &vtun) < 0) - return FALSE; - if (strcmp (vtun.name, v4lelement->vchan.name)) - return FALSE; - - if (ioctl (v4lelement->video_fd, VIDIOCGFREQ, frequency) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting tuner frequency: %s", g_strerror (errno))); - return FALSE; - } - - *frequency = *frequency * channel->freq_multiplicator; - - return TRUE; -} - - -/****************************************************** - * gst_v4l_set_frequency(): - * set frequency - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_frequency (GstV4lElement * v4lelement, - gint tunernum, gulong frequency) -{ - struct video_tuner vtun; - GstTunerChannel *channel; - - GST_DEBUG_OBJECT (v4lelement, "setting tuner frequency to %lu", frequency); - GST_V4L_CHECK_OPEN (v4lelement); - - channel = gst_tuner_get_channel (GST_TUNER (v4lelement)); - - /* check that this is the current input */ - vtun.tuner = tunernum; - if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &vtun) < 0) - return FALSE; - if (strcmp (vtun.name, v4lelement->vchan.name)) - return FALSE; - - frequency = frequency / channel->freq_multiplicator; - - if (ioctl (v4lelement->video_fd, VIDIOCSFREQ, &frequency) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting tuner frequency: %s", g_strerror (errno))); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_get_picture(): - * get a picture value - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_picture (GstV4lElement * v4lelement, - GstV4lPictureType type, gint * value) -{ - struct video_picture vpic; - - GST_DEBUG_OBJECT (v4lelement, "getting picture property type %d (%s)", type, - picture_name[type]); - GST_V4L_CHECK_OPEN (v4lelement); - - if (ioctl (v4lelement->video_fd, VIDIOCGPICT, &vpic) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting picture parameters: %s", g_strerror (errno))); - return FALSE; - } - - switch (type) { - case V4L_PICTURE_HUE: - *value = vpic.hue; - break; - case V4L_PICTURE_BRIGHTNESS: - *value = vpic.brightness; - break; - case V4L_PICTURE_CONTRAST: - *value = vpic.contrast; - break; - case V4L_PICTURE_SATURATION: - *value = vpic.colour; - break; - default: - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting picture parameters: unknown type %d", type)); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_set_picture(): - * set a picture value - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_picture (GstV4lElement * v4lelement, - GstV4lPictureType type, gint value) -{ - struct video_picture vpic; - - GST_DEBUG_OBJECT (v4lelement, "setting picture type %d (%s) to value %d", - type, picture_name[type], value); - GST_V4L_CHECK_OPEN (v4lelement); - - if (ioctl (v4lelement->video_fd, VIDIOCGPICT, &vpic) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting picture parameters: %s", g_strerror (errno))); - return FALSE; - } - - switch (type) { - case V4L_PICTURE_HUE: - vpic.hue = value; - break; - case V4L_PICTURE_BRIGHTNESS: - vpic.brightness = value; - break; - case V4L_PICTURE_CONTRAST: - vpic.contrast = value; - break; - case V4L_PICTURE_SATURATION: - vpic.colour = value; - break; - default: - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting picture parameters: unknown type %d", type)); - return FALSE; - } - - if (ioctl (v4lelement->video_fd, VIDIOCSPICT, &vpic) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting picture parameters: %s", g_strerror (errno))); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_get_audio(): - * get some audio value - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_audio (GstV4lElement * v4lelement, - gint audionum, GstV4lAudioType type, gint * value) -{ - struct video_audio vau; - - GST_DEBUG_OBJECT (v4lelement, "getting audio parameter type %d (%s)", type, - audio_name[type]); - GST_V4L_CHECK_OPEN (v4lelement); - - vau.audio = audionum; - if (ioctl (v4lelement->video_fd, VIDIOCGAUDIO, &vau) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting audio parameters: %s", g_strerror (errno))); - return FALSE; - } - - switch (type) { - case V4L_AUDIO_MUTE: - *value = (vau.flags & VIDEO_AUDIO_MUTE); - break; - case V4L_AUDIO_VOLUME: - *value = vau.volume; - break; - case V4L_AUDIO_MODE: - *value = vau.mode; - break; - default: - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting audio parameters: unknown type %d", type)); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_set_audio(): - * set some audio value - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_audio (GstV4lElement * v4lelement, - gint audionum, GstV4lAudioType type, gint value) -{ - struct video_audio vau; - - GST_DEBUG_OBJECT (v4lelement, - "setting audio parameter type %d (%s) to value %d", type, - audio_name[type], value); - GST_V4L_CHECK_OPEN (v4lelement); - - vau.audio = audionum; - if (ioctl (v4lelement->video_fd, VIDIOCGAUDIO, &vau) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting audio parameters: %s", g_strerror (errno))); - return FALSE; - } - - switch (type) { - case V4L_AUDIO_MUTE: - if (!(vau.flags & VIDEO_AUDIO_MUTABLE)) { - GST_ELEMENT_ERROR (v4lelement, CORE, NOT_IMPLEMENTED, (NULL), - ("Error setting audio mute: (un)setting mute is not supported")); - return FALSE; - } - if (value) - vau.flags |= VIDEO_AUDIO_MUTE; - else - vau.flags &= ~VIDEO_AUDIO_MUTE; - break; - case V4L_AUDIO_VOLUME: - if (!(vau.flags & VIDEO_AUDIO_VOLUME)) { - GST_ELEMENT_ERROR (v4lelement, CORE, NOT_IMPLEMENTED, (NULL), - ("Error setting audio volume: setting volume is not supported")); - return FALSE; - } - vau.volume = value; - break; - case V4L_AUDIO_MODE: - vau.mode = value; - break; - default: - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting audio parameters: unknown type %d", type)); - return FALSE; - } - - if (ioctl (v4lelement->video_fd, VIDIOCSAUDIO, &vau) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting audio parameters: %s", g_strerror (errno))); - return FALSE; - } - - return TRUE; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/v4l_calls.h --- a/gst_plugins_base/sys/v4l/v4l_calls.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* GStreamer - * - * v4l_calls.h: header for generic V4L calls - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifndef __V4L_CALLS_H__ -#define __V4L_CALLS_H__ - -#include "gstv4lelement.h" -#include "gst/gst-i18n-plugin.h" - - -G_BEGIN_DECLS - - -/* simple check whether the device is open */ -#define GST_V4L_IS_OPEN(element) \ - (GST_V4LELEMENT (element)->video_fd > 0) - -/* check whether the device is 'active' */ -#define GST_V4L_IS_ACTIVE(element) \ - (GST_V4LELEMENT (element)->buffer != NULL) - -#define GST_V4L_IS_OVERLAY(element) \ - (GST_V4LELEMENT (element)->vcap.type & VID_TYPE_OVERLAY) - -/* checks whether the current v4lelement has already been open()'ed or not */ -#define GST_V4L_CHECK_OPEN(element) \ - if (!GST_V4L_IS_OPEN (element)) \ - { \ - GST_ELEMENT_ERROR (element, RESOURCE, TOO_LAZY, \ - (_("Device is not open.")), (NULL)); \ - return FALSE; \ - } - -/* checks whether the current v4lelement is close()'ed or whether it is still open */ -#define GST_V4L_CHECK_NOT_OPEN(element) \ - if (GST_V4L_IS_OPEN (element)) \ - { \ - GST_ELEMENT_ERROR (element, RESOURCE, TOO_LAZY, \ - (_("Device is open.")), (NULL)); \ - return FALSE; \ - } - -/* checks whether the current v4lelement does video overlay */ -#define GST_V4L_CHECK_OVERLAY(element) \ - if (!(element->vcap.type & VID_TYPE_OVERLAY)) \ - { \ - GST_ELEMENT_ERROR (element, RESOURCE, TOO_LAZY, \ - (NULL), ("Device cannot handle overlay")); \ - return FALSE; \ - } - -/* checks whether we're in capture mode or not */ -#define GST_V4L_CHECK_ACTIVE(element) \ - if (!GST_V4L_IS_ACTIVE (element)) \ - { \ - GST_ELEMENT_ERROR (element, RESOURCE, SETTINGS, \ - (NULL), ("Device is not in streaming mode")); \ - return FALSE; \ - } - -/* checks whether we're out of capture mode or not */ -#define GST_V4L_CHECK_NOT_ACTIVE(element) \ - if (GST_V4L_IS_ACTIVE (element)) \ - { \ - GST_ELEMENT_ERROR (element, RESOURCE, SETTINGS, \ - (NULL), ("Device is in streaming mode")); \ - return FALSE; \ - } - - -typedef enum { - V4L_PICTURE_HUE = 0, - V4L_PICTURE_BRIGHTNESS, - V4L_PICTURE_CONTRAST, - V4L_PICTURE_SATURATION, -} GstV4lPictureType; - -typedef enum { - V4L_AUDIO_VOLUME = 0, - V4L_AUDIO_MUTE, - V4L_AUDIO_MODE, /* stereo, mono, ... (see videodev.h) */ -} GstV4lAudioType; - - -/* open/close the device */ -gboolean gst_v4l_open (GstV4lElement *v4lelement); -gboolean gst_v4l_close (GstV4lElement *v4lelement); - -/* norm control (norm = VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}) */ -gboolean gst_v4l_get_chan_norm (GstV4lElement *v4lelement, - gint *channel, - gint *norm); -gboolean gst_v4l_set_chan_norm (GstV4lElement *v4lelement, - gint channel, - gint norm); -GList *gst_v4l_get_chan_names (GstV4lElement *v4lelement); - -/* frequency control */ -gboolean gst_v4l_get_signal (GstV4lElement *v4lelement, - gint tunernum, - guint *signal); -gboolean gst_v4l_get_frequency (GstV4lElement *v4lelement, - gint tunernum, - gulong *frequency); -gboolean gst_v4l_set_frequency (GstV4lElement *v4lelement, - gint tunernum, - gulong frequency); - -/* picture control */ -gboolean gst_v4l_get_picture (GstV4lElement *v4lelement, - GstV4lPictureType type, - gint *value); -gboolean gst_v4l_set_picture (GstV4lElement *v4lelement, - GstV4lPictureType type, - gint value); - -/* audio control */ -gboolean gst_v4l_get_audio (GstV4lElement *v4lelement, - gint audionum, - GstV4lAudioType type, - gint *value); -gboolean gst_v4l_set_audio (GstV4lElement *v4lelement, - gint audionum, - GstV4lAudioType type, - gint value); - -/* functions that v4lsrc needs */ -gboolean gst_v4l_set_window_properties (GstV4lElement * v4lelement); -gboolean gst_v4l_get_capabilities (GstV4lElement * v4lelement); - - -G_END_DECLS - - -#endif /* __V4L_CALLS_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/v4lmjpegsink_calls.h --- a/gst_plugins_base/sys/v4l/v4lmjpegsink_calls.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* GStreamer - * - * v4lmjpegsink_calls.c: functions for hardware MJPEG video sink - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifndef __V4L_MJPEG_SINK_CALLS_H__ -#define __V4L_MJPEG_SINK_CALLS_H__ - -#include "gstv4lmjpegsink.h" -#include "v4l_calls.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -/* frame playback on device */ -gboolean gst_v4lmjpegsink_set_buffer (GstV4lMjpegSink *v4lmjpegsink, - gint numbufs, - gint bufsize); -gboolean gst_v4lmjpegsink_set_playback (GstV4lMjpegSink *v4lmjpegsink, - gint width, - gint height, - gint x_offset, - gint y_offset, - gint norm, - gint interlacing); -gboolean gst_v4lmjpegsink_playback_init (GstV4lMjpegSink *v4lmjpegsink); -gboolean gst_v4lmjpegsink_playback_start (GstV4lMjpegSink *v4lmjpegsink); -guint8 * gst_v4lmjpegsink_get_buffer (GstV4lMjpegSink *v4lmjpegsink, - gint num); -gboolean gst_v4lmjpegsink_play_frame (GstV4lMjpegSink *v4lmjpegsink, - gint num); -gboolean gst_v4lmjpegsink_wait_frame (GstV4lMjpegSink *v4lmjpegsink, - gint *num); -gboolean gst_v4lmjpegsink_playback_stop (GstV4lMjpegSink *v4lmjpegsink); -gboolean gst_v4lmjpegsink_playback_deinit (GstV4lMjpegSink *v4lmjpegsink); - - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __V4L_MJPEG_SINK_CALLS_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/v4lmjpegsrc_calls.h --- a/gst_plugins_base/sys/v4l/v4lmjpegsrc_calls.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* GStreamer - * - * v4lmjpegsrc_calls.h: functions for hardware MJPEG video source - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifndef __V4L_MJPEG_SRC_CALLS_H__ -#define __V4L_MJPEG_SRC_CALLS_H__ - -#include "gstv4lmjpegsrc.h" -#include "v4l_calls.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -/* frame grabbing/capture */ -gboolean gst_v4lmjpegsrc_set_buffer (GstV4lMjpegSrc *v4lmjpegsrc, - gint numbufs, - gint bufsize); -gboolean gst_v4lmjpegsrc_set_capture (GstV4lMjpegSrc *v4lmjpegsrc, - gint decimation, - gint quality); -gboolean gst_v4lmjpegsrc_set_capture_m (GstV4lMjpegSrc *v4lmjpegsrc, - gint x_offset, - gint y_offset, - gint width, - gint height, - gint h_decimation, - gint v_decimation, - gint quality); -gboolean gst_v4lmjpegsrc_capture_init (GstV4lMjpegSrc *v4lmjpegsrc); -gboolean gst_v4lmjpegsrc_capture_start (GstV4lMjpegSrc *v4lmjpegsrc); -gboolean gst_v4lmjpegsrc_grab_frame (GstV4lMjpegSrc *v4lmjpegsrc, - gint *num, - gint *size); -guint8 * gst_v4lmjpegsrc_get_buffer (GstV4lMjpegSrc *v4lmjpegsrc, - gint num); -gboolean gst_v4lmjpegsrc_requeue_frame (GstV4lMjpegSrc *v4lmjpegsrc, - gint num); -gboolean gst_v4lmjpegsrc_capture_stop (GstV4lMjpegSrc *v4lmjpegsrc); -gboolean gst_v4lmjpegsrc_capture_deinit (GstV4lMjpegSrc *v4lmjpegsrc); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __V4L_MJPEG_SRC_CALLS_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/v4lsrc_calls.c --- a/gst_plugins_base/sys/v4l/v4lsrc_calls.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,740 +0,0 @@ -/* GStreamer - * - * v4lsrc_calls.c: generic V4L source functions - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include "v4lsrc_calls.h" -#include - -/* number of buffers to be queued *at least* before syncing */ -#define MIN_BUFFERS_QUEUED 2 - -/* On some systems MAP_FAILED seems to be missing */ -#ifndef MAP_FAILED -#define MAP_FAILED ( (caddr_t) -1 ) -#endif - -GST_DEBUG_CATEGORY_EXTERN (v4l_debug); - -#define GST_CAT_DEFAULT v4l_debug - -#ifndef GST_DISABLE_GST_DEBUG -/* palette names */ -static const char *v4l_palette_name[] = { - "", /* 0 */ - "grayscale", /* VIDEO_PALETTE_GREY */ - "Hi-420", /* VIDEO_PALETTE_HI420 */ - "16-bit RGB (RGB-565)", /* VIDEO_PALETTE_RB565 */ - "24-bit RGB", /* VIDEO_PALETTE_RGB24 */ - "32-bit RGB", /* VIDEO_PALETTE_RGB32 */ - "15-bit RGB (RGB-555)", /* VIDEO_PALETTE_RGB555 */ - "YUV-4:2:2 (packed)", /* VIDEO_PALETTE_YUV422 */ - "YUYV", /* VIDEO_PALETTE_YUYV */ - "UYVY", /* VIDEO_PALETTE_UYVY */ - "YUV-4:2:0 (packed)", /* VIDEO_PALETTE_YUV420 */ - "YUV-4:1:1 (packed)", /* VIDEO_PALETTE_YUV411 */ - "Raw", /* VIDEO_PALETTE_RAW */ - "YUV-4:2:2 (planar)", /* VIDEO_PALETTE_YUV422P */ - "YUV-4:1:1 (planar)", /* VIDEO_PALETTE_YUV411P */ - "YUV-4:2:0 (planar)/I420", /* VIDEO_PALETTE_YUV420P */ - "YUV-4:1:0 (planar)" /* VIDEO_PALETTE_YUV410P */ -}; -#endif - -/****************************************************** - * gst_v4lsrc_queue_frame(): - * queue a frame for capturing - * (ie. instruct the hardware to start capture) - * Requires queue_state lock to be held! - * return value: TRUE on success, FALSE on error - ******************************************************/ - -static gboolean -gst_v4lsrc_queue_frame (GstV4lSrc * v4lsrc, gint num) -{ - GST_LOG_OBJECT (v4lsrc, "queueing frame %d", num); - - if (v4lsrc->frame_queue_state[num] != QUEUE_STATE_READY_FOR_QUEUE) { - return FALSE; - } - - /* instruct the driver to prepare capture using buffer frame num */ - v4lsrc->mmap.frame = num; - if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, - VIDIOCMCAPTURE, &(v4lsrc->mmap)) < 0) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, WRITE, (NULL), - ("Error queueing a buffer (%d): %s", num, g_strerror (errno))); - return FALSE; - } - - v4lsrc->frame_queue_state[num] = QUEUE_STATE_QUEUED; - v4lsrc->num_queued++; - - return TRUE; -} - -/****************************************************** - * gst_v4lsrc_hard_sync_frame(GstV4lSrc *v4lsrc,gint num) - * sync a frame and set the timestamp correctly - * Requires queue_state lock to be held - *****************************************************/ - -static gboolean -gst_v4lsrc_sync_frame (GstV4lSrc * v4lsrc, gint num) -{ - GST_LOG_OBJECT (v4lsrc, "VIOIOCSYNC on frame %d", num); - - if (v4lsrc->frame_queue_state[num] != QUEUE_STATE_QUEUED) { - return FALSE; - } - - while (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCSYNC, &num) < 0) { - /* if the sync() got interrupted, we can retry */ - if (errno != EINTR) { - v4lsrc->frame_queue_state[num] = QUEUE_STATE_ERROR; - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, SYNC, (NULL), GST_ERROR_SYSTEM); - return FALSE; - } - GST_DEBUG_OBJECT (v4lsrc, "Sync got interrupted"); - } - GST_LOG_OBJECT (v4lsrc, "VIOIOCSYNC on frame %d done", num); - - v4lsrc->frame_queue_state[num] = QUEUE_STATE_SYNCED; - v4lsrc->num_queued--; - - return TRUE; -} - -/****************************************************** - * gst_v4lsrc_set_capture(): - * set capture parameters, palette = VIDEO_PALETTE_* - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_set_capture (GstV4lSrc * v4lsrc, - gint width, gint height, gint palette) -{ - GST_DEBUG_OBJECT (v4lsrc, - "capture properties set to %dx%d, palette %d", width, height, palette); - - v4lsrc->mmap.width = width; - v4lsrc->mmap.height = height; - v4lsrc->mmap.format = palette; - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_capture_init(): - * initialize the capture system - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_capture_init (GstV4lSrc * v4lsrc) -{ - GST_DEBUG_OBJECT (v4lsrc, "initting capture subsystem"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - /* request the mmap buffer info: - * total size of mmap buffer, number of frames, offsets of frames */ - if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCGMBUF, - &(v4lsrc->mbuf)) < 0) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, READ, (NULL), - ("Error getting buffer information: %s", g_strerror (errno))); - return FALSE; - } - - if (v4lsrc->mbuf.frames < MIN_BUFFERS_QUEUED) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, READ, (NULL), - ("Not enough buffers. We got %d, we want at least %d", - v4lsrc->mbuf.frames, MIN_BUFFERS_QUEUED)); - return FALSE; - } - - GST_INFO_OBJECT (v4lsrc, "Got %d buffers (\'%s\') with total size %d KB", - v4lsrc->mbuf.frames, v4l_palette_name[v4lsrc->mmap.format], - v4lsrc->mbuf.size / (v4lsrc->mbuf.frames * 1024)); - - /* keep track of queued buffers */ - v4lsrc->frame_queue_state = (gint8 *) - g_malloc (sizeof (gint8) * v4lsrc->mbuf.frames); - - /* lock for the frame_state */ - v4lsrc->mutex_queue_state = g_mutex_new (); - v4lsrc->cond_queue_state = g_cond_new (); - - /* Map the buffers */ - GST_V4LELEMENT (v4lsrc)->buffer = mmap (NULL, v4lsrc->mbuf.size, - PROT_READ | PROT_WRITE, MAP_SHARED, GST_V4LELEMENT (v4lsrc)->video_fd, 0); - if (GST_V4LELEMENT (v4lsrc)->buffer == MAP_FAILED) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, OPEN_READ_WRITE, (NULL), - ("Error mapping video buffers: %s", g_strerror (errno))); - GST_V4LELEMENT (v4lsrc)->buffer = NULL; - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_capture_start(): - * start streaming capture - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_capture_start (GstV4lSrc * v4lsrc) -{ - int n; - - GST_DEBUG_OBJECT (v4lsrc, "starting capture"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - g_mutex_lock (v4lsrc->mutex_queue_state); - - v4lsrc->quit = FALSE; - v4lsrc->num_queued = 0; - v4lsrc->sync_frame = 0; - v4lsrc->queue_frame = 0; - - /* set all buffers ready to queue, and queue captures to the device. - * This starts streaming capture */ - for (n = 0; n < v4lsrc->mbuf.frames; n++) { - v4lsrc->frame_queue_state[n] = QUEUE_STATE_READY_FOR_QUEUE; - if (!gst_v4lsrc_queue_frame (v4lsrc, n)) { - g_mutex_unlock (v4lsrc->mutex_queue_state); - gst_v4lsrc_capture_stop (v4lsrc); - return FALSE; - } - } - - v4lsrc->is_capturing = TRUE; - g_mutex_unlock (v4lsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_grab_frame(): - * capture one frame during streaming capture - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_grab_frame (GstV4lSrc * v4lsrc, gint * num) -{ - GST_LOG_OBJECT (v4lsrc, "grabbing frame %d", *num); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - g_mutex_lock (v4lsrc->mutex_queue_state); - - /* do we have enough frames? */ - while (v4lsrc->num_queued < MIN_BUFFERS_QUEUED || - v4lsrc->frame_queue_state[v4lsrc->queue_frame] == - QUEUE_STATE_READY_FOR_QUEUE) { - while (v4lsrc->frame_queue_state[v4lsrc->queue_frame] != - QUEUE_STATE_READY_FOR_QUEUE && !v4lsrc->quit) { - GST_DEBUG_OBJECT (v4lsrc, - "Waiting for frames to become available (queued %d < minimum %d)", - v4lsrc->num_queued, MIN_BUFFERS_QUEUED); - g_cond_wait (v4lsrc->cond_queue_state, v4lsrc->mutex_queue_state); - } - if (v4lsrc->quit) { - g_mutex_unlock (v4lsrc->mutex_queue_state); - return FALSE; - } - if (!gst_v4lsrc_queue_frame (v4lsrc, v4lsrc->queue_frame)) { - g_mutex_unlock (v4lsrc->mutex_queue_state); - return FALSE; - } - v4lsrc->queue_frame = (v4lsrc->queue_frame + 1) % v4lsrc->mbuf.frames; - } - - /* syncing on the buffer grabs it */ - *num = v4lsrc->sync_frame; - if (!gst_v4lsrc_sync_frame (v4lsrc, *num)) { - g_mutex_unlock (v4lsrc->mutex_queue_state); - return FALSE; - } - v4lsrc->sync_frame = (v4lsrc->sync_frame + 1) % v4lsrc->mbuf.frames; - - g_mutex_unlock (v4lsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_get_buffer(): - * get the address of the given frame number in the mmap'd buffer - * return value: the buffer's address or NULL - ******************************************************/ - -guint8 * -gst_v4lsrc_get_buffer (GstV4lSrc * v4lsrc, gint num) -{ - if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)) || - !GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) - return NULL; - - if (num < 0 || num >= v4lsrc->mbuf.frames) - return NULL; - - return GST_V4LELEMENT (v4lsrc)->buffer + v4lsrc->mbuf.offsets[num]; -} - - -/****************************************************** - * gst_v4lsrc_requeue_frame(): - * re-queue a frame after we're done with the buffer - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_requeue_frame (GstV4lSrc * v4lsrc, gint num) -{ - GST_LOG_OBJECT (v4lsrc, "requeueing frame %d", num); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - /* mark frame as 'ready to requeue' */ - g_mutex_lock (v4lsrc->mutex_queue_state); - - if (v4lsrc->frame_queue_state[num] != QUEUE_STATE_SYNCED) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, TOO_LAZY, (NULL), - ("Invalid state %d (expected %d), can't requeue", - v4lsrc->frame_queue_state[num], QUEUE_STATE_SYNCED)); - return FALSE; - } - - v4lsrc->frame_queue_state[num] = QUEUE_STATE_READY_FOR_QUEUE; - - /* let an optional wait know */ - g_cond_broadcast (v4lsrc->cond_queue_state); - - g_mutex_unlock (v4lsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_capture_stop(): - * stop streaming capture - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_capture_stop (GstV4lSrc * v4lsrc) -{ - GST_DEBUG_OBJECT (v4lsrc, "stopping capture"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - g_mutex_lock (v4lsrc->mutex_queue_state); - v4lsrc->is_capturing = FALSE; - - /* make an optional pending wait stop */ - v4lsrc->quit = TRUE; - g_cond_broadcast (v4lsrc->cond_queue_state); - - /* sync on remaining frames */ - while (1) { - if (v4lsrc->frame_queue_state[v4lsrc->sync_frame] == QUEUE_STATE_QUEUED) { - gst_v4lsrc_sync_frame (v4lsrc, v4lsrc->sync_frame); - v4lsrc->sync_frame = (v4lsrc->sync_frame + 1) % v4lsrc->mbuf.frames; - } else { - break; - } - } - - g_mutex_unlock (v4lsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_capture_deinit(): - * deinitialize the capture system - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_capture_deinit (GstV4lSrc * v4lsrc) -{ - GST_DEBUG_OBJECT (v4lsrc, "quitting capture subsystem"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - /* free buffer tracker */ - g_mutex_free (v4lsrc->mutex_queue_state); - v4lsrc->mutex_queue_state = NULL; - g_cond_free (v4lsrc->cond_queue_state); - v4lsrc->cond_queue_state = NULL; - g_free (v4lsrc->frame_queue_state); - v4lsrc->frame_queue_state = NULL; - - /* unmap the buffer */ - if (munmap (GST_V4LELEMENT (v4lsrc)->buffer, v4lsrc->mbuf.size) == -1) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, CLOSE, (NULL), - ("error munmap'ing capture buffer: %s", g_strerror (errno))); - return FALSE; - } - GST_V4LELEMENT (v4lsrc)->buffer = NULL; - - return TRUE; -} - -/****************************************************** - * gst_v4lsrc_try_capture(): - * try out a capture on the device - * This has to be done before initializing the - * actual capture system, to make sure we don't - * mess up anything. So we need to mini-mmap() - * a buffer here, queue and sync on one buffer, - * and unmap it. - * This is ugly, yes, I know - but it's a major - * design flaw of v4l1 that you don't know in - * advance which formats will be supported... - * This is better than "just assuming that it'll - * work"... - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_try_capture (GstV4lSrc * v4lsrc, gint width, gint height, - gint palette) -{ - /* so, we need a buffer and some more stuff */ - int frame = 0; - guint8 *buffer; - struct video_mbuf vmbuf; - struct video_mmap vmmap; - - GST_DEBUG_OBJECT (v4lsrc, "try out %dx%d, palette format %d (%s)", - width, height, palette, v4l_palette_name[palette]); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - /* let's start by requesting a buffer and mmap()'ing it */ - if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCGMBUF, &vmbuf) < 0) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, READ, (NULL), - ("Error getting buffer information: %s", g_strerror (errno))); - return FALSE; - } - /* Map the buffers */ - buffer = mmap (NULL, vmbuf.size, PROT_READ | PROT_WRITE, - MAP_SHARED, GST_V4LELEMENT (v4lsrc)->video_fd, 0); - if (buffer == MAP_FAILED) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, OPEN_READ_WRITE, (NULL), - ("Error mapping our try-out buffer: %s", g_strerror (errno))); - return FALSE; - } - - /* now that we have a buffer, let's try out our format */ - vmmap.width = width; - vmmap.height = height; - vmmap.format = palette; - vmmap.frame = frame; - if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCMCAPTURE, &vmmap) < 0) { - if (errno != EINVAL) /* our format failed! */ - GST_ERROR_OBJECT (v4lsrc, - "Error queueing our try-out buffer: %s", g_strerror (errno)); - munmap (buffer, vmbuf.size); - return FALSE; - } - - if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCSYNC, &frame) < 0) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, SYNC, (NULL), GST_ERROR_SYSTEM); - munmap (buffer, vmbuf.size); - return FALSE; - } - - munmap (buffer, vmbuf.size); - - /* if we got here, it worked! woohoo, the format is supported! */ - return TRUE; -} - -#ifndef GST_DISABLE_GST_DEBUG -const char * -gst_v4lsrc_palette_name (int i) -{ - return v4l_palette_name[i]; -} -#endif - -gboolean -gst_v4lsrc_get_fps (GstV4lSrc * v4lsrc, gint * fps_n, gint * fps_d) -{ - gint norm; - gint fps_index; - struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin; - - /* check if we have vwin window properties giving a framerate, - * as is done for webcams - * See http://www.smcc.demon.nl/webcam/api.html - * which is used for the Philips and qce-ga drivers */ - fps_index = (vwin->flags >> 16) & 0x3F; /* 6 bit index for framerate */ - - /* webcams have a non-zero fps_index */ - if (fps_index != 0) { - /* index of 16 corresponds to 15 fps */ - GST_DEBUG_OBJECT (v4lsrc, "device reports fps of %d/%d (%.4f)", - fps_index * 15, 16, fps_index * 15.0 / 16); - - if (fps_n) - *fps_n = fps_index * 15; - if (fps_d) - *fps_d = 16; - - return TRUE; - } - - /* removed fps estimation code here */ - - /* if that failed ... */ - - if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) - return FALSE; - - if (!gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lsrc), NULL, &norm)) - return FALSE; - - if (norm == VIDEO_MODE_NTSC) { - if (fps_n) - *fps_n = 30000; - if (fps_d) - *fps_d = 1001; - } else { - if (fps_n) - *fps_n = 25; - if (fps_d) - *fps_d = 1; - } - - return TRUE; -} - -/* get a list of possible framerates - * this is only done for webcams; - * other devices return NULL here. - * this function takes a LONG time to execute. - */ -GValue * -gst_v4lsrc_get_fps_list (GstV4lSrc * v4lsrc) -{ - gint fps_index; - struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin; - GstV4lElement *v4lelement = GST_V4LELEMENT (v4lsrc); - - /* check if we have vwin window properties giving a framerate, - * as is done for webcams - * See http://www.smcc.demon.nl/webcam/api.html - * which is used for the Philips and qce-ga drivers */ - fps_index = (vwin->flags >> 16) & 0x3F; /* 6 bit index for framerate */ - - /* webcams have a non-zero fps_index */ - if (fps_index == 0) { - GST_DEBUG_OBJECT (v4lsrc, "fps_index is 0, no webcam"); - return NULL; - } - GST_DEBUG_OBJECT (v4lsrc, "fps_index is %d, so webcam", fps_index); - - { - int i; - GValue *list = NULL; - GValue value = { 0 }; - - /* webcam detected, so try all framerates and return a list */ - - list = g_new0 (GValue, 1); - g_value_init (list, GST_TYPE_LIST); - - /* index of 16 corresponds to 15 fps */ - GST_DEBUG_OBJECT (v4lsrc, "device reports fps of %d/%d (%.4f)", - fps_index * 15, 16, fps_index * 15.0 / 16); - for (i = 0; i < 63; ++i) { - /* set bits 16 to 21 to 0 */ - vwin->flags &= (0x3F00 - 1); - /* set bits 16 to 21 to the index */ - vwin->flags |= i << 16; - if (gst_v4l_set_window_properties (v4lelement)) { - /* setting it succeeded. FIXME: get it and check. */ - g_value_init (&value, GST_TYPE_FRACTION); - gst_value_set_fraction (&value, i * 15, 16); - gst_value_list_append_value (list, &value); - g_value_unset (&value); - } - } - /* FIXME: set back the original fps_index */ - vwin->flags &= (0x3F00 - 1); - vwin->flags |= fps_index << 16; - gst_v4l_set_window_properties (v4lelement); - return list; - } - return NULL; -} - -#define GST_TYPE_V4LSRC_BUFFER (gst_v4lsrc_buffer_get_type()) -#define GST_IS_V4LSRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4LSRC_BUFFER)) -#define GST_V4LSRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4LSRC_BUFFER, GstV4lSrcBuffer)) - -typedef struct _GstV4lSrcBuffer -{ - GstBuffer buffer; - - GstV4lSrc *v4lsrc; - - gint num; -} GstV4lSrcBuffer; - -static void gst_v4lsrc_buffer_class_init (gpointer g_class, - gpointer class_data); -static void gst_v4lsrc_buffer_init (GTypeInstance * instance, gpointer g_class); -static void gst_v4lsrc_buffer_finalize (GstV4lSrcBuffer * v4lsrc_buffer); - -static GstBufferClass *v4lbuffer_parent_class = NULL; - -static GType -gst_v4lsrc_buffer_get_type (void) -{ - static GType _gst_v4lsrc_buffer_type; - - if (G_UNLIKELY (_gst_v4lsrc_buffer_type == 0)) { - static const GTypeInfo v4lsrc_buffer_info = { - sizeof (GstBufferClass), - NULL, - NULL, - gst_v4lsrc_buffer_class_init, - NULL, - NULL, - sizeof (GstV4lSrcBuffer), - 0, - gst_v4lsrc_buffer_init, - NULL - }; - _gst_v4lsrc_buffer_type = g_type_register_static (GST_TYPE_BUFFER, - "GstV4lSrcBuffer", &v4lsrc_buffer_info, 0); - } - return _gst_v4lsrc_buffer_type; -} - -static void -gst_v4lsrc_buffer_class_init (gpointer g_class, gpointer class_data) -{ - GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); - - v4lbuffer_parent_class = g_type_class_peek_parent (g_class); - - mini_object_class->finalize = (GstMiniObjectFinalizeFunction) - gst_v4lsrc_buffer_finalize; -} - -static void -gst_v4lsrc_buffer_init (GTypeInstance * instance, gpointer g_class) -{ - -} - -static void -gst_v4lsrc_buffer_finalize (GstV4lSrcBuffer * v4lsrc_buffer) -{ - GstV4lSrc *v4lsrc; - gint num; - - v4lsrc = v4lsrc_buffer->v4lsrc; - num = v4lsrc_buffer->num; - - GST_LOG_OBJECT (v4lsrc, "freeing buffer %p for frame %d", v4lsrc_buffer, num); - - /* only requeue if we still have an mmap buffer */ - if (GST_V4LELEMENT (v4lsrc)->buffer) { - GST_LOG_OBJECT (v4lsrc, "requeueing frame %d", num); - gst_v4lsrc_requeue_frame (v4lsrc, num); - } - - gst_object_unref (v4lsrc); - - GST_MINI_OBJECT_CLASS (v4lbuffer_parent_class)-> - finalize (GST_MINI_OBJECT (v4lsrc_buffer)); -} - -/* Create a V4lSrc buffer from our mmap'd data area */ -GstBuffer * -gst_v4lsrc_buffer_new (GstV4lSrc * v4lsrc, gint num) -{ - GstBuffer *buf; - gint fps_n, fps_d; - GstClockTime duration, timestamp, latency; - - GST_DEBUG_OBJECT (v4lsrc, "creating buffer for frame %d", num); - - g_return_val_if_fail (gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d), NULL); - - buf = (GstBuffer *) gst_mini_object_new (GST_TYPE_V4LSRC_BUFFER); - - GST_V4LSRC_BUFFER (buf)->num = num; - GST_V4LSRC_BUFFER (buf)->v4lsrc = gst_object_ref (v4lsrc); - - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY); - GST_BUFFER_DATA (buf) = gst_v4lsrc_get_buffer (v4lsrc, num); - GST_BUFFER_SIZE (buf) = v4lsrc->buffer_size; - GST_BUFFER_OFFSET (buf) = v4lsrc->offset++; - - duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n); - latency = duration; - - timestamp = gst_clock_get_time (GST_ELEMENT_CAST (v4lsrc)->clock); - timestamp -= gst_element_get_base_time (GST_ELEMENT_CAST (v4lsrc)); - if (timestamp > latency) - timestamp -= latency; - else - timestamp = 0; - - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_DURATION (buf) = duration; - - /* the negotiate() method already set caps on the source pad */ - gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (v4lsrc))); - - return buf; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/v4lsrc_calls.h --- a/gst_plugins_base/sys/v4l/v4lsrc_calls.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* GStreamer - * - * v4lsrc_calls.h: functions for V4L video source - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * 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. - */ - -#ifndef __V4L_SRC_CALLS_H__ -#define __V4L_SRC_CALLS_H__ - -#include "gstv4lsrc.h" -#include "v4l_calls.h" - - -G_BEGIN_DECLS - - -/* frame grabbing/capture (palette = VIDEO_PALETTE_* - see videodev.h) */ -gboolean gst_v4lsrc_set_capture (GstV4lSrc *v4lsrc, gint width, gint height, gint palette); -gboolean gst_v4lsrc_capture_init (GstV4lSrc *v4lsrc); -gboolean gst_v4lsrc_capture_start (GstV4lSrc *v4lsrc); -gboolean gst_v4lsrc_grab_frame (GstV4lSrc *v4lsrc, gint *num); -guint8 * gst_v4lsrc_get_buffer (GstV4lSrc *v4lsrc, gint num); -gboolean gst_v4lsrc_requeue_frame (GstV4lSrc *v4lsrc, gint num); -gboolean gst_v4lsrc_capture_stop (GstV4lSrc *v4lsrc); -gboolean gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc); -gboolean gst_v4lsrc_get_fps (GstV4lSrc * v4lsrc, gint *fps_n, gint *fps_d); -GValue * gst_v4lsrc_get_fps_list (GstV4lSrc * v4lsrc); -GstBuffer *gst_v4lsrc_buffer_new (GstV4lSrc * v4lsrc, gint num); - -/* "the ugliest hack ever, now available at your local mirror" */ -gboolean gst_v4lsrc_try_capture (GstV4lSrc *v4lsrc, gint width, gint height, gint palette); - -/* For debug purposes, share the palette names */ -#ifndef GST_DISABLE_GST_DEBUG -const char *gst_v4lsrc_palette_name (int i); -#endif - - -G_END_DECLS - - -#endif /* __V4L_SRC_CALLS_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/v4l/videodev_mjpeg.h --- a/gst_plugins_base/sys/v4l/videodev_mjpeg.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* These are the MJPEG API extensions for the Video4Linux API, - first introduced by the Iomega Buz driver by Rainer Johanni - -*/ - -#ifndef __VIDEODEV_MJPEG_H__ -#define __VIDEODEV_MJPEG_H__ - -/* This is identical with the mgavideo internal params struct, - please tell me if you change this struct here ! top-field-first */ - - int APPn; /* Number of APP segment to be written, must be 0..15 */ - int APP_len; /* Length of data in JPEG APPn segment */ - char APP_data[60]; /* Data in the JPEG APPn segment. */ - - int COM_len; /* Length of data in JPEG COM segment */ - char COM_data[60]; /* Data in JPEG COM segment */ - - unsigned long jpeg_markers; /* Which markers should go into the JPEG output. - Unless you exactly know what you do, leave them untouched. - Inluding less markers will make the resulting code - smaller, but there will be fewer applications - which can read it. - The presence of the APP and COM marker is - influenced by APP0_len and COM_len ONLY! */ -#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ -#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ -#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ -#define JPEG_MARKER_COM (1<<6) /* Comment segment */ -#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ - - int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. - If this flag is turned on and JPEG decompressing - is going to the screen, the decompress process - is stopped every time the Video Fifo is full. - This enables a smooth decompress to the screen - but the video output signal will get scrambled */ - - /* Misc */ - - char reserved[312]; /* Makes 512 bytes for this structure */ -}; - -struct mjpeg_requestbuffers -{ - unsigned long count; /* Number of buffers for MJPEG grabbing */ - unsigned long size; /* Size PER BUFFER in bytes */ -}; - -struct mjpeg_sync -{ - unsigned long frame; /* Frame (0 - n) for double buffer */ - unsigned long length; /* number of code bytes in buffer (capture only) */ - unsigned long seq; /* frame sequence number */ - struct timeval timestamp; /* timestamp */ -}; - -struct mjpeg_status -{ - int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ - int signal; /* Returned: 1 if valid video signal detected */ - int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ - int color; /* Returned: 1 if color signal detected */ -}; - -/* -Private IOCTL to set up for displaying MJPEG -*/ -#define MJPIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct mjpeg_params) -#define MJPIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct mjpeg_params) -#define MJPIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct mjpeg_requestbuffers) -#define MJPIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) -#define MJPIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) -#define MJPIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct mjpeg_sync) -#define MJPIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct mjpeg_status) - -#endif /* __VIDEODEV_MJPEG_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/ximage/ximage.c --- a/gst_plugins_base/sys/ximage/ximage.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* GStreamer - * Copyright (C) <2003> Julien Moutte - * - * 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. - */ - - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "ximagesink.h" - -GST_DEBUG_CATEGORY (gst_debug_ximagesink); - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "ximagesink", - GST_RANK_SECONDARY, GST_TYPE_XIMAGESINK)) - return FALSE; - - GST_DEBUG_CATEGORY_INIT (gst_debug_ximagesink, "ximagesink", 0, - "ximagesink element"); - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "ximagesink", - "X11 video output element based on standard Xlib calls", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/ximage/ximagesink.c --- a/gst_plugins_base/sys/ximage/ximagesink.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2324 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Julien Moutte - * - * 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. - */ - -/** - * SECTION:element-ximagesink - * - * - * - * XImageSink renders video frames to a drawable (XWindow) on a local or remote - * display. This element can receive a Window ID from the application through - * the XOverlay interface and will then render video frames in this drawable. - * If no Window ID was provided by the application, the element will create its - * own internal window and render into it. - * - * Scaling - * - * As standard XImage rendering to a drawable is not scaled, XImageSink will use - * reverse caps negotiation to try to get scaled video frames for the drawable. - * This is accomplished by asking the peer pad if it accepts some different caps - * which in most cases implies that there is a scaling element in the pipeline, - * or that an element generating the video frames can generate them with a - * different geometry. This mechanism is handled during buffer allocations, for - * each allocation request the video sink will check the drawable geometry, look - * at the - * force-aspect-ratio - * property, calculate the geometry of desired video frames and then check that - * the peer pad accept those new caps. If it does it will then allocate a buffer - * in video memory with this new geometry and return it with the new caps. - * - * Events - * - * XImageSink creates a thread to handle events coming from the drawable. There - * are several kind of events that can be grouped in 2 big categories: input - * events and window state related events. Input events will be translated to - * navigation events and pushed upstream for other elements to react on them. - * This includes events such as pointer moves, key press/release, clicks etc... - * Other events are used to handle the drawable appearance even when the data - * is not flowing (GST_STATE_PAUSED). That means that even when the element is - * paused, it will receive expose events from the drawable and draw the latest - * frame with correct borders/aspect-ratio. - * - * Pixel aspect ratio - * - * When changing state to GST_STATE_READY, XImageSink will open a connection to - * the display specified in the - * display property or the default - * display if nothing specified. Once this connection is open it will inspect - * the display configuration including the physical display geometry and - * then calculate the pixel aspect ratio. When caps negotiation will occur, the - * video sink will set the calculated pixel aspect ratio on the caps to make - * sure that incoming video frames will have the correct pixel aspect ratio for - * this display. Sometimes the calculated pixel aspect ratio can be wrong, it is - * then possible to enforce a specific pixel aspect ratio using the - * pixel-aspect-ratio - * property. - * - * Examples - * - * Here is a simple pipeline to test reverse negotiation : - * - * gst-launch -v videotestsrc ! queue ! ximagesink - * - * When the test video signal appears you can resize the window and see that - * scaled buffers of the desired size are going to arrive with a short delay. - * This illustrates how buffers of desired size are allocated along the way. - * If you take away the queue, scaling will happen almost immediately. - * - * - * Here is a simple pipeline to test navigation events : - * - * gst-launch -v videotestsrc ! navigationtest ! ffmpegcolorspace ! ximagesink - * - * While moving the mouse pointer over the test signal you will see a black box - * following the mouse pointer. If you press the mouse button somewhere on the - * video and release it somewhere else a green box will appear where you pressed - * the button and a red one where you released it. (The navigationtest element - * is part of gst-plugins-good.) - * - * - * Here is a simple pipeline to test pixel aspect ratio : - * - * gst-launch -v videotestsrc ! video/x-raw-rgb, pixel-aspect-ratio=(fraction)4/3 ! videoscale ! ximagesink - * - * This is faking a 4/3 pixel aspect ratio caps on video frames produced by - * videotestsrc, in most cases the pixel aspect ratio of the display will be - * 1/1. This means that videoscale will have to do the scaling to convert - * incoming frames to a size that will match the display pixel aspect ratio - * (from 320x240 to 320x180 in this case). Note that you might have to escape - * some characters for your shell like '\(fraction\)'. - * - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* Our interfaces */ -#include -#include - -/* Object header */ -#include "ximagesink.h" - -/* Debugging category */ -#include - -GST_DEBUG_CATEGORY_EXTERN (gst_debug_ximagesink); -#define GST_CAT_DEFAULT gst_debug_ximagesink - -typedef struct -{ - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long input_mode; - unsigned long status; -} -MotifWmHints, MwmHints; - -#define MWM_HINTS_DECORATIONS (1L << 1) - -static void gst_ximagesink_reset (GstXImageSink * ximagesink); -static void gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink, - GstXImageBuffer * ximage); -static void gst_ximagesink_xwindow_update_geometry (GstXImageSink * ximagesink, - GstXWindow * xwindow); -static void gst_ximagesink_expose (GstXOverlay * overlay); - -/* ElementFactory information */ -static const GstElementDetails gst_ximagesink_details = -GST_ELEMENT_DETAILS ("Video sink", - "Sink/Video", - "A standard X based videosink", - "Julien Moutte "); - -static GstStaticPadTemplate gst_ximagesink_sink_template_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw-rgb, " - "framerate = (fraction) [ 0, MAX ], " - "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]") - ); - -enum -{ - PROP_0, - PROP_DISPLAY, - PROP_SYNCHRONOUS, - PROP_PIXEL_ASPECT_RATIO, - PROP_FORCE_ASPECT_RATIO, - PROP_HANDLE_EVENTS, - PROP_HANDLE_EXPOSE -}; - -static GstVideoSinkClass *parent_class = NULL; - -/* ============================================================= */ -/* */ -/* Private Methods */ -/* */ -/* ============================================================= */ - -/* ximage buffers */ - -static GstBufferClass *ximage_buffer_parent_class = NULL; - -#define GST_TYPE_XIMAGE_BUFFER (gst_ximage_buffer_get_type()) - -#define GST_IS_XIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XIMAGE_BUFFER)) -#define GST_XIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XIMAGE_BUFFER, GstXImageBuffer)) -#define GST_XIMAGE_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XIMAGE_BUFFER, GstXImageBufferClass)) - -/* So some words about GstMiniObject, this is pretty messy... - GstMiniObject does not use the standard finalizing of GObjects, you are - supposed to call gst_buffer_unref that's going to call gst_mini_objec_unref - which will handle its own refcount system and call gst_mini_object_free. - gst_mini_object_free will call the class finalize method which is not the - one from GObject, after calling this finalize method it will free the object - instance for you if the refcount is still 0 so you should not chain up */ -static void -gst_ximage_buffer_finalize (GstXImageBuffer * ximage) -{ - GstXImageSink *ximagesink = NULL; - gboolean recycled = FALSE; - gboolean running; - - g_return_if_fail (ximage != NULL); - - ximagesink = ximage->ximagesink; - if (G_UNLIKELY (ximagesink == NULL)) { - GST_WARNING_OBJECT (ximagesink, "no sink found"); - goto beach; - } - - GST_OBJECT_LOCK (ximagesink); - running = ximagesink->running; - GST_OBJECT_UNLOCK (ximagesink); - - if (running == FALSE) { - /* If the sink is shutting down, need to clear the image */ - GST_DEBUG_OBJECT (ximagesink, - "destroy image %p because the sink is shutting down", ximage); - gst_ximagesink_ximage_destroy (ximagesink, ximage); - } else if ((ximage->width != GST_VIDEO_SINK_WIDTH (ximagesink)) || - (ximage->height != GST_VIDEO_SINK_HEIGHT (ximagesink))) { - /* If our geometry changed we can't reuse that image. */ - GST_DEBUG_OBJECT (ximagesink, - "destroy image %p as its size changed %dx%d vs current %dx%d", - ximage, ximage->width, ximage->height, - GST_VIDEO_SINK_WIDTH (ximagesink), GST_VIDEO_SINK_HEIGHT (ximagesink)); - gst_ximagesink_ximage_destroy (ximagesink, ximage); - } else { - /* In that case we can reuse the image and add it to our image pool. */ - GST_LOG_OBJECT (ximagesink, "recycling image %p in pool", ximage); - /* need to increment the refcount again to recycle */ - gst_buffer_ref (GST_BUFFER_CAST (ximage)); - g_mutex_lock (ximagesink->pool_lock); - ximagesink->buffer_pool = g_slist_prepend (ximagesink->buffer_pool, ximage); - g_mutex_unlock (ximagesink->pool_lock); - recycled = TRUE; - } - - if (!recycled) - GST_MINI_OBJECT_CLASS (ximage_buffer_parent_class)-> - finalize (GST_MINI_OBJECT (ximage)); - -beach: - return; -} - -static void -gst_ximage_buffer_free (GstXImageBuffer * ximage) -{ - /* make sure it is not recycled */ - ximage->width = -1; - ximage->height = -1; - gst_buffer_unref (GST_BUFFER_CAST (ximage)); -} - -static void -gst_ximage_buffer_init (GstXImageBuffer * ximage_buffer, gpointer g_class) -{ -#ifdef HAVE_XSHM - ximage_buffer->SHMInfo.shmaddr = ((void *) -1); - ximage_buffer->SHMInfo.shmid = -1; -#endif -} - -static void -gst_ximage_buffer_class_init (gpointer g_class, gpointer class_data) -{ - GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); - - ximage_buffer_parent_class = g_type_class_peek_parent (g_class); - - mini_object_class->finalize = (GstMiniObjectFinalizeFunction) - gst_ximage_buffer_finalize; -} - -static GType -gst_ximage_buffer_get_type (void) -{ - static GType _gst_ximage_buffer_type; - - if (G_UNLIKELY (_gst_ximage_buffer_type == 0)) { - static const GTypeInfo ximage_buffer_info = { - sizeof (GstBufferClass), - NULL, - NULL, - gst_ximage_buffer_class_init, - NULL, - NULL, - sizeof (GstXImageBuffer), - 0, - (GInstanceInitFunc) gst_ximage_buffer_init, - NULL - }; - _gst_ximage_buffer_type = g_type_register_static (GST_TYPE_BUFFER, - "GstXImageBuffer", &ximage_buffer_info, 0); - } - return _gst_ximage_buffer_type; -} - -/* X11 stuff */ - -static gboolean error_caught = FALSE; - -static int -gst_ximagesink_handle_xerror (Display * display, XErrorEvent * xevent) -{ - char error_msg[1024]; - - XGetErrorText (display, xevent->error_code, error_msg, 1024); - GST_DEBUG ("ximagesink triggered an XError. error: %s", error_msg); - error_caught = TRUE; - return 0; -} - -#ifdef HAVE_XSHM /* Check that XShm calls actually work */ - -static gboolean -gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink, - GstXContext * xcontext) -{ - XImage *ximage; - XShmSegmentInfo SHMInfo; - size_t size; - int (*handler) (Display *, XErrorEvent *); - gboolean result = FALSE; - gboolean did_attach = FALSE; - - g_return_val_if_fail (xcontext != NULL, FALSE); - - /* Sync to ensure any older errors are already processed */ - XSync (xcontext->disp, FALSE); - - /* Set defaults so we don't free these later unnecessarily */ - SHMInfo.shmaddr = ((void *) -1); - SHMInfo.shmid = -1; - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_ximagesink_handle_xerror); - - /* Trying to create a 1x1 ximage */ - GST_DEBUG ("XShmCreateImage of 1x1"); - - ximage = XShmCreateImage (xcontext->disp, xcontext->visual, - xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1); - - /* Might cause an error, sync to ensure it is noticed */ - XSync (xcontext->disp, FALSE); - if (!ximage || error_caught) { - GST_WARNING ("could not XShmCreateImage a 1x1 image"); - goto beach; - } - size = ximage->height * ximage->bytes_per_line; - - SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); - if (SHMInfo.shmid == -1) { - GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", - size); - goto beach; - } - - SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0); - if (SHMInfo.shmaddr == ((void *) -1)) { - GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); - /* Clean up shm seg */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - /* Delete the shared memory segment as soon as we manage to attach. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - - ximage->data = SHMInfo.shmaddr; - SHMInfo.readOnly = FALSE; - - if (XShmAttach (xcontext->disp, &SHMInfo) == 0) { - GST_WARNING ("Failed to XShmAttach"); - goto beach; - } - - /* Sync to ensure we see any errors we caused */ - XSync (xcontext->disp, FALSE); - - if (!error_caught) { - did_attach = TRUE; - /* store whether we succeeded in result */ - result = TRUE; - } - -beach: - /* Sync to ensure we swallow any errors we caused and reset error_caught */ - XSync (xcontext->disp, FALSE); - error_caught = FALSE; - XSetErrorHandler (handler); - - if (did_attach) { - XShmDetach (xcontext->disp, &SHMInfo); - XSync (xcontext->disp, FALSE); - } - if (SHMInfo.shmaddr != ((void *) -1)) - shmdt (SHMInfo.shmaddr); - if (ximage) - XDestroyImage (ximage); - return result; -} -#endif /* HAVE_XSHM */ - -/* This function handles GstXImageBuffer creation depending on XShm availability */ -static GstXImageBuffer * -gst_ximagesink_ximage_new (GstXImageSink * ximagesink, GstCaps * caps) -{ - GstXImageBuffer *ximage = NULL; - GstStructure *structure = NULL; - gboolean succeeded = FALSE; - int (*handler) (Display *, XErrorEvent *); - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); - - ximage = (GstXImageBuffer *) gst_mini_object_new (GST_TYPE_XIMAGE_BUFFER); - - structure = gst_caps_get_structure (caps, 0); - - if (!gst_structure_get_int (structure, "width", &ximage->width) || - !gst_structure_get_int (structure, "height", &ximage->height)) { - GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps); - } - - GST_DEBUG_OBJECT (ximagesink, "creating image %p (%dx%d)", ximage, - ximage->width, ximage->height); - - g_mutex_lock (ximagesink->x_lock); - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_ximagesink_handle_xerror); - -#ifdef HAVE_XSHM - if (ximagesink->xcontext->use_xshm) { - ximage->ximage = XShmCreateImage (ximagesink->xcontext->disp, - ximagesink->xcontext->visual, - ximagesink->xcontext->depth, - ZPixmap, NULL, &ximage->SHMInfo, ximage->width, ximage->height); - if (!ximage->ximage || error_caught) { - g_mutex_unlock (ximagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximage->width, ximage->height), - ("could not XShmCreateImage a %dx%d image", - ximage->width, ximage->height)); - goto beach; - } - - /* we have to use the returned bytes_per_line for our shm size */ - ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height; - GST_LOG_OBJECT (ximagesink, - "XShm image size is %" G_GSIZE_FORMAT ", width %d, stride %d", - ximage->size, ximage->width, ximage->ximage->bytes_per_line); - - ximage->SHMInfo.shmid = shmget (IPC_PRIVATE, ximage->size, - IPC_CREAT | 0777); - if (ximage->SHMInfo.shmid == -1) { - g_mutex_unlock (ximagesink->x_lock); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximage->width, ximage->height), - ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", - ximage->size)); - goto beach; - } - - ximage->SHMInfo.shmaddr = shmat (ximage->SHMInfo.shmid, NULL, 0); - if (ximage->SHMInfo.shmaddr == ((void *) -1)) { - g_mutex_unlock (ximagesink->x_lock); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximage->width, ximage->height), - ("Failed to shmat: %s", g_strerror (errno))); - /* Clean up the shared memory segment */ - shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - /* Now that we've attached, we can delete the shared memory segment. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL); - - ximage->ximage->data = ximage->SHMInfo.shmaddr; - ximage->SHMInfo.readOnly = FALSE; - - if (XShmAttach (ximagesink->xcontext->disp, &ximage->SHMInfo) == 0) { - g_mutex_unlock (ximagesink->x_lock); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximage->width, ximage->height), ("Failed to XShmAttach")); - goto beach; - } - - XSync (ximagesink->xcontext->disp, FALSE); - } else -#endif /* HAVE_XSHM */ - { - guint allocsize; - - ximage->ximage = XCreateImage (ximagesink->xcontext->disp, - ximagesink->xcontext->visual, - ximagesink->xcontext->depth, - ZPixmap, 0, NULL, - ximage->width, ximage->height, ximagesink->xcontext->bpp, 0); - if (!ximage->ximage || error_caught) { - g_mutex_unlock (ximagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximage->width, ximage->height), - ("could not XCreateImage a %dx%d image", - ximage->width, ximage->height)); - goto beach; - } - - /* upstream will assume that rowstrides are multiples of 4, but this - * doesn't always seem to be the case with XCreateImage() */ - if ((ximage->ximage->bytes_per_line % 4) != 0) { - GST_WARNING_OBJECT (ximagesink, "returned stride not a multiple of 4 as " - "usually assumed"); - } - - /* we have to use the returned bytes_per_line for our image size */ - ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height; - - /* alloc a bit more for unexpected strides to avoid crashes upstream. - * FIXME: if we get an unrounded stride, the image will be displayed - * distorted, since all upstream elements assume a rounded stride */ - allocsize = - GST_ROUND_UP_4 (ximage->ximage->bytes_per_line) * - ximage->ximage->height; - ximage->ximage->data = g_malloc (allocsize); - GST_LOG_OBJECT (ximagesink, - "non-XShm image size is %" G_GSIZE_FORMAT " (alloced: %u), width %d, " - "stride %d", ximage->size, allocsize, ximage->width, - ximage->ximage->bytes_per_line); - - XSync (ximagesink->xcontext->disp, FALSE); - } - - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - - succeeded = TRUE; - - GST_BUFFER_DATA (ximage) = (guchar *) ximage->ximage->data; - GST_BUFFER_SIZE (ximage) = ximage->size; - - /* Keep a ref to our sink */ - ximage->ximagesink = gst_object_ref (ximagesink); - - g_mutex_unlock (ximagesink->x_lock); -beach: - if (!succeeded) { - gst_ximage_buffer_free (ximage); - ximage = NULL; - } - - return ximage; -} - -/* This function destroys a GstXImageBuffer handling XShm availability */ -static void -gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink, - GstXImageBuffer * ximage) -{ - g_return_if_fail (ximage != NULL); - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - /* Hold the object lock to ensure the XContext doesn't disappear */ - GST_OBJECT_LOCK (ximagesink); - - /* If the destroyed image is the current one we destroy our reference too */ - if (ximagesink->cur_image == ximage) { - ximagesink->cur_image = NULL; - } - - /* We might have some buffers destroyed after changing state to NULL */ - if (!ximagesink->xcontext) { - GST_DEBUG_OBJECT (ximagesink, "Destroying XImage after XContext"); -#ifdef HAVE_XSHM - if (ximage->SHMInfo.shmaddr != ((void *) -1)) { - shmdt (ximage->SHMInfo.shmaddr); - } -#endif - goto beach; - } - - g_mutex_lock (ximagesink->x_lock); - -#ifdef HAVE_XSHM - if (ximagesink->xcontext->use_xshm) { - if (ximage->SHMInfo.shmaddr != ((void *) -1)) { - XShmDetach (ximagesink->xcontext->disp, &ximage->SHMInfo); - XSync (ximagesink->xcontext->disp, 0); - shmdt (ximage->SHMInfo.shmaddr); - } - if (ximage->ximage) - XDestroyImage (ximage->ximage); - - } else -#endif /* HAVE_XSHM */ - { - if (ximage->ximage) { - XDestroyImage (ximage->ximage); - } - } - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - -beach: - GST_OBJECT_UNLOCK (ximagesink); - - if (ximage->ximagesink) { - /* Release the ref to our sink */ - ximage->ximagesink = NULL; - gst_object_unref (ximagesink); - } - - return; -} - -/* We are called with the x_lock taken */ -static void -gst_ximagesink_xwindow_draw_borders (GstXImageSink * ximagesink, - GstXWindow * xwindow, GstVideoRectangle rect) -{ - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - g_return_if_fail (xwindow != NULL); - - XSetForeground (ximagesink->xcontext->disp, xwindow->gc, - ximagesink->xcontext->black); - - /* Left border */ - if (rect.x > 0) { - XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, rect.x, xwindow->height); - } - - /* Right border */ - if ((rect.x + rect.w) < xwindow->width) { - XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc, - rect.x + rect.w, 0, xwindow->width, xwindow->height); - } - - /* Top border */ - if (rect.y > 0) { - XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, xwindow->width, rect.y); - } - - /* Bottom border */ - if ((rect.y + rect.h) < xwindow->height) { - XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, rect.y + rect.h, xwindow->width, xwindow->height); - } -} - -/* This function puts a GstXImageBuffer on a GstXImageSink's window */ -static gboolean -gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage) -{ - GstVideoRectangle src, dst, result; - gboolean draw_border = FALSE; - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), FALSE); - - /* We take the flow_lock. If expose is in there we don't want to run - concurrently from the data flow thread */ - g_mutex_lock (ximagesink->flow_lock); - - if (G_UNLIKELY (ximagesink->xwindow == NULL)) { - g_mutex_unlock (ximagesink->flow_lock); - return FALSE; - } - - /* Draw borders when displaying the first frame. After this - draw borders only on expose event. */ - if (!ximagesink->cur_image) { - draw_border = TRUE; - } - - /* Store a reference to the last image we put, lose the previous one */ - if (ximage && ximagesink->cur_image != ximage) { - if (ximagesink->cur_image) { - GST_LOG_OBJECT (ximagesink, "unreffing %p", ximagesink->cur_image); - gst_buffer_unref (ximagesink->cur_image); - } - GST_LOG_OBJECT (ximagesink, "reffing %p as our current image", ximage); - ximagesink->cur_image = - GST_XIMAGE_BUFFER (gst_buffer_ref (GST_BUFFER_CAST (ximage))); - } - - /* Expose sends a NULL image, we take the latest frame */ - if (!ximage) { - draw_border = TRUE; - if (ximagesink->cur_image) { - ximage = ximagesink->cur_image; - } else { - g_mutex_unlock (ximagesink->flow_lock); - return TRUE; - } - } - - gst_ximagesink_xwindow_update_geometry (ximagesink, ximagesink->xwindow); - - src.w = ximage->width; - src.h = ximage->height; - dst.w = ximagesink->xwindow->width; - dst.h = ximagesink->xwindow->height; - - gst_video_sink_center_rect (src, dst, &result, FALSE); - - g_mutex_lock (ximagesink->x_lock); - - if (draw_border) { - gst_ximagesink_xwindow_draw_borders (ximagesink, ximagesink->xwindow, - result); - } -#ifdef HAVE_XSHM - if (ximagesink->xcontext->use_xshm) { - GST_LOG_OBJECT (ximagesink, - "XShmPutImage on %p, src: %d, %d - dest: %d, %d, dim: %dx%d, win %dx%d", - ximage, 0, 0, result.x, result.y, result.w, result.h, - ximagesink->xwindow->width, ximagesink->xwindow->height); - XShmPutImage (ximagesink->xcontext->disp, ximagesink->xwindow->win, - ximagesink->xwindow->gc, ximage->ximage, 0, 0, result.x, result.y, - result.w, result.h, FALSE); - } else -#endif /* HAVE_XSHM */ - { - GST_LOG_OBJECT (ximagesink, - "XPutImage on %p, src: %d, %d - dest: %d, %d, dim: %dx%d, win %dx%d", - ximage, 0, 0, result.x, result.y, result.w, result.h, - ximagesink->xwindow->width, ximagesink->xwindow->height); - XPutImage (ximagesink->xcontext->disp, ximagesink->xwindow->win, - ximagesink->xwindow->gc, ximage->ximage, 0, 0, result.x, result.y, - result.w, result.h); - } - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - - g_mutex_unlock (ximagesink->flow_lock); - - return TRUE; -} - -static gboolean -gst_ximagesink_xwindow_decorate (GstXImageSink * ximagesink, - GstXWindow * window) -{ - Atom hints_atom = None; - MotifWmHints *hints; - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), FALSE); - g_return_val_if_fail (window != NULL, FALSE); - - g_mutex_lock (ximagesink->x_lock); - - hints_atom = XInternAtom (ximagesink->xcontext->disp, "_MOTIF_WM_HINTS", 1); - if (hints_atom == None) { - g_mutex_unlock (ximagesink->x_lock); - return FALSE; - } - - hints = g_malloc0 (sizeof (MotifWmHints)); - - hints->flags |= MWM_HINTS_DECORATIONS; - hints->decorations = 1 << 0; - - XChangeProperty (ximagesink->xcontext->disp, window->win, - hints_atom, hints_atom, 32, PropModeReplace, - (guchar *) hints, sizeof (MotifWmHints) / sizeof (long)); - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - - g_free (hints); - - return TRUE; -} - -/* This function handles a GstXWindow creation */ -static GstXWindow * -gst_ximagesink_xwindow_new (GstXImageSink * ximagesink, gint width, gint height) -{ - GstXWindow *xwindow = NULL; - XGCValues values; - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); - - xwindow = g_new0 (GstXWindow, 1); - - xwindow->width = width; - xwindow->height = height; - xwindow->internal = TRUE; - - g_mutex_lock (ximagesink->x_lock); - - xwindow->win = XCreateSimpleWindow (ximagesink->xcontext->disp, - ximagesink->xcontext->root, - 0, 0, xwindow->width, xwindow->height, 0, 0, ximagesink->xcontext->black); - - /* We have to do that to prevent X from redrawing the background on - ConfigureNotify. This takes away flickering of video when resizing. */ - XSetWindowBackgroundPixmap (ximagesink->xcontext->disp, xwindow->win, None); - - if (ximagesink->handle_events) { - Atom wm_delete; - - XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - - /* Tell the window manager we'd like delete client messages instead of - * being killed */ - wm_delete = XInternAtom (ximagesink->xcontext->disp, - "WM_DELETE_WINDOW", False); - (void) XSetWMProtocols (ximagesink->xcontext->disp, xwindow->win, - &wm_delete, 1); - } - - xwindow->gc = XCreateGC (ximagesink->xcontext->disp, xwindow->win, - 0, &values); - - XMapRaised (ximagesink->xcontext->disp, xwindow->win); - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - - gst_ximagesink_xwindow_decorate (ximagesink, xwindow); - - gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (ximagesink), xwindow->win); - - return xwindow; -} - -/* This function destroys a GstXWindow */ -static void -gst_ximagesink_xwindow_destroy (GstXImageSink * ximagesink, - GstXWindow * xwindow) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - g_mutex_lock (ximagesink->x_lock); - - /* If we did not create that window we just free the GC and let it live */ - if (xwindow->internal) - XDestroyWindow (ximagesink->xcontext->disp, xwindow->win); - else - XSelectInput (ximagesink->xcontext->disp, xwindow->win, 0); - - XFreeGC (ximagesink->xcontext->disp, xwindow->gc); - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - - g_free (xwindow); -} - -static void -gst_ximagesink_xwindow_update_geometry (GstXImageSink * ximagesink, - GstXWindow * xwindow) -{ - XWindowAttributes attr; - - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - /* Update the window geometry */ - g_mutex_lock (ximagesink->x_lock); - - XGetWindowAttributes (ximagesink->xcontext->disp, - ximagesink->xwindow->win, &attr); - - ximagesink->xwindow->width = attr.width; - ximagesink->xwindow->height = attr.height; - - g_mutex_unlock (ximagesink->x_lock); -} - -static void -gst_ximagesink_xwindow_clear (GstXImageSink * ximagesink, GstXWindow * xwindow) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - g_mutex_lock (ximagesink->x_lock); - - XSetForeground (ximagesink->xcontext->disp, xwindow->gc, - ximagesink->xcontext->black); - - XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, xwindow->width, xwindow->height); - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); -} - -/* This function handles XEvents that might be in the queue. It generates - GstEvent that will be sent upstream in the pipeline to handle interactivity - and navigation.*/ -static void -gst_ximagesink_handle_xevents (GstXImageSink * ximagesink) -{ - XEvent e; - guint pointer_x = 0, pointer_y = 0; - gboolean pointer_moved = FALSE; - gboolean exposed = FALSE, configured = FALSE; - - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - /* Then we get all pointer motion events, only the last position is - interesting. */ - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - while (XCheckWindowEvent (ximagesink->xcontext->disp, - ximagesink->xwindow->win, PointerMotionMask, &e)) { - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); - - switch (e.type) { - case MotionNotify: - pointer_x = e.xmotion.x; - pointer_y = e.xmotion.y; - pointer_moved = TRUE; - break; - default: - break; - } - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - } - - if (pointer_moved) { - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); - - GST_DEBUG ("ximagesink pointer moved over window at %d,%d", - pointer_x, pointer_y); - gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink), - "mouse-move", 0, pointer_x, pointer_y); - - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - } - - /* We get all remaining events on our window to throw them upstream */ - while (XCheckWindowEvent (ximagesink->xcontext->disp, - ximagesink->xwindow->win, - KeyPressMask | KeyReleaseMask | - ButtonPressMask | ButtonReleaseMask, &e)) { - KeySym keysym; - - /* We lock only for the X function call */ - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); - - switch (e.type) { - case ButtonPress: - /* Mouse button pressed/released over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("ximagesink button %d pressed over window at %d,%d", - e.xbutton.button, e.xbutton.x, e.xbutton.x); - gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink), - "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y); - break; - case ButtonRelease: - GST_DEBUG ("ximagesink button %d release over window at %d,%d", - e.xbutton.button, e.xbutton.x, e.xbutton.x); - gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink), - "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y); - break; - case KeyPress: - case KeyRelease: - /* Key pressed/released over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("ximagesink key %d pressed over window at %d,%d", - e.xkey.keycode, e.xkey.x, e.xkey.x); - g_mutex_lock (ximagesink->x_lock); - keysym = XKeycodeToKeysym (ximagesink->xcontext->disp, - e.xkey.keycode, 0); - g_mutex_unlock (ximagesink->x_lock); - if (keysym != NoSymbol) { - char *key_str = NULL; - - g_mutex_lock (ximagesink->x_lock); - key_str = XKeysymToString (keysym); - g_mutex_unlock (ximagesink->x_lock); - gst_navigation_send_key_event (GST_NAVIGATION (ximagesink), - e.type == KeyPress ? "key-press" : "key-release", key_str); - - } else { - gst_navigation_send_key_event (GST_NAVIGATION (ximagesink), - e.type == KeyPress ? "key-press" : "key-release", "unknown"); - } - break; - default: - GST_DEBUG_OBJECT (ximagesink, "ximagesink unhandled X event (%d)", - e.type); - } - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - } - - while (XCheckWindowEvent (ximagesink->xcontext->disp, - ximagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) { - switch (e.type) { - case Expose: - exposed = TRUE; - break; - case ConfigureNotify: - configured = TRUE; - break; - default: - break; - } - } - - if (ximagesink->handle_expose && (exposed || configured)) { - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); - - gst_ximagesink_expose (GST_X_OVERLAY (ximagesink)); - - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - } - - /* Handle Display events */ - while (XPending (ximagesink->xcontext->disp)) { - XNextEvent (ximagesink->xcontext->disp, &e); - - switch (e.type) { - case ClientMessage:{ - Atom wm_delete; - - wm_delete = XInternAtom (ximagesink->xcontext->disp, - "WM_DELETE_WINDOW", False); - if (wm_delete == (Atom) e.xclient.data.l[0]) { - /* Handle window deletion by posting an error on the bus */ - GST_ELEMENT_ERROR (ximagesink, RESOURCE, NOT_FOUND, - ("Output window was closed"), (NULL)); - - g_mutex_unlock (ximagesink->x_lock); - gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow); - ximagesink->xwindow = NULL; - g_mutex_lock (ximagesink->x_lock); - } - break; - } - default: - break; - } - } - - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); -} - -static gpointer -gst_ximagesink_event_thread (GstXImageSink * ximagesink) -{ - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); - - GST_OBJECT_LOCK (ximagesink); - while (ximagesink->running) { - GST_OBJECT_UNLOCK (ximagesink); - - if (ximagesink->xwindow) { - gst_ximagesink_handle_xevents (ximagesink); - } - g_usleep (100000); - - GST_OBJECT_LOCK (ximagesink); - } - GST_OBJECT_UNLOCK (ximagesink); - - return NULL; -} - -/* This function calculates the pixel aspect ratio based on the properties - * in the xcontext structure and stores it there. */ -static void -gst_ximagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext) -{ - static const gint par[][2] = { - {1, 1}, /* regular screen */ - {16, 15}, /* PAL TV */ - {11, 10}, /* 525 line Rec.601 video */ - {54, 59}, /* 625 line Rec.601 video */ - {64, 45}, /* 1280x1024 on 16:9 display */ - {5, 3}, /* 1280x1024 on 4:3 display */ - {4, 3} /* 800x600 on 16:9 display */ - }; - gint i; - gint index; - gdouble ratio; - gdouble delta; - -#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1]))) - - /* first calculate the "real" ratio based on the X values; - * which is the "physical" w/h divided by the w/h in pixels of the display */ - ratio = (gdouble) (xcontext->widthmm * xcontext->height) - / (xcontext->heightmm * xcontext->width); - - /* DirectFB's X in 720x576 reports the physical dimensions wrong, so - * override here */ - if (xcontext->width == 720 && xcontext->height == 576) { - ratio = 4.0 * 576 / (3.0 * 720); - } - GST_DEBUG ("calculated pixel aspect ratio: %f", ratio); - - /* now find the one from par[][2] with the lowest delta to the real one */ - delta = DELTA (0); - index = 0; - - for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) { - gdouble this_delta = DELTA (i); - - if (this_delta < delta) { - index = i; - delta = this_delta; - } - } - - GST_DEBUG ("Decided on index %d (%d/%d)", index, - par[index][0], par[index][1]); - - g_free (xcontext->par); - xcontext->par = g_new0 (GValue, 1); - g_value_init (xcontext->par, GST_TYPE_FRACTION); - gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]); - GST_DEBUG ("set xcontext PAR to %d/%d", - gst_value_get_fraction_numerator (xcontext->par), - gst_value_get_fraction_denominator (xcontext->par)); -} - -/* This function gets the X Display and global info about it. Everything is - stored in our object and will be cleaned when the object is disposed. Note - here that caps for supported format are generated without any window or - image creation */ -static GstXContext * -gst_ximagesink_xcontext_get (GstXImageSink * ximagesink) -{ - GstXContext *xcontext = NULL; - XPixmapFormatValues *px_formats = NULL; - gint nb_formats = 0, i; - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); - - xcontext = g_new0 (GstXContext, 1); - - g_mutex_lock (ximagesink->x_lock); - - xcontext->disp = XOpenDisplay (ximagesink->display_name); - - if (!xcontext->disp) { - g_mutex_unlock (ximagesink->x_lock); - g_free (xcontext); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Could not initialise X output"), ("Could not open display")); - return NULL; - } - - xcontext->screen = DefaultScreenOfDisplay (xcontext->disp); - xcontext->screen_num = DefaultScreen (xcontext->disp); - xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num); - xcontext->root = DefaultRootWindow (xcontext->disp); - xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num); - xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num); - xcontext->depth = DefaultDepthOfScreen (xcontext->screen); - - xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num); - xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num); - xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num); - xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num); - - GST_DEBUG_OBJECT (ximagesink, "X reports %dx%d pixels and %d mm x %d mm", - xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm); - - gst_ximagesink_calculate_pixel_aspect_ratio (xcontext); - - /* We get supported pixmap formats at supported depth */ - px_formats = XListPixmapFormats (xcontext->disp, &nb_formats); - - if (!px_formats) { - XCloseDisplay (xcontext->disp); - g_mutex_unlock (ximagesink->x_lock); - g_free (xcontext->par); - g_free (xcontext); - return NULL; - } - - /* We get bpp value corresponding to our running depth */ - for (i = 0; i < nb_formats; i++) { - if (px_formats[i].depth == xcontext->depth) - xcontext->bpp = px_formats[i].bits_per_pixel; - } - - XFree (px_formats); - - xcontext->endianness = - (ImageByteOrder (xcontext->disp) == - LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN; - - /* Search for XShm extension support */ -#ifdef HAVE_XSHM - if (XShmQueryExtension (xcontext->disp) && - gst_ximagesink_check_xshm_calls (ximagesink, xcontext)) { - xcontext->use_xshm = TRUE; - GST_DEBUG ("ximagesink is using XShm extension"); - } else -#endif - { - xcontext->use_xshm = FALSE; - GST_DEBUG ("ximagesink is not using XShm extension"); - } - - /* our caps system handles 24/32bpp RGB as big-endian. */ - if ((xcontext->bpp == 24 || xcontext->bpp == 32) && - xcontext->endianness == G_LITTLE_ENDIAN) { - xcontext->endianness = G_BIG_ENDIAN; - xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask); - xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask); - xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask); - if (xcontext->bpp == 24) { - xcontext->visual->red_mask >>= 8; - xcontext->visual->green_mask >>= 8; - xcontext->visual->blue_mask >>= 8; - } - } - - /* update object's par with calculated one if not set yet */ - if (!ximagesink->par) { - ximagesink->par = g_new0 (GValue, 1); - gst_value_init_and_copy (ximagesink->par, xcontext->par); - GST_DEBUG_OBJECT (ximagesink, "set calculated PAR on object's PAR"); - } - xcontext->caps = gst_caps_new_simple ("video/x-raw-rgb", - "bpp", G_TYPE_INT, xcontext->bpp, - "depth", G_TYPE_INT, xcontext->depth, - "endianness", G_TYPE_INT, xcontext->endianness, - "red_mask", G_TYPE_INT, xcontext->visual->red_mask, - "green_mask", G_TYPE_INT, xcontext->visual->green_mask, - "blue_mask", G_TYPE_INT, xcontext->visual->blue_mask, - "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - if (ximagesink->par) { - int nom, den; - - nom = gst_value_get_fraction_numerator (ximagesink->par); - den = gst_value_get_fraction_denominator (ximagesink->par); - gst_caps_set_simple (xcontext->caps, "pixel-aspect-ratio", - GST_TYPE_FRACTION, nom, den, NULL); - } - - g_mutex_unlock (ximagesink->x_lock); - - /* Setup our event listening thread */ - GST_OBJECT_LOCK (ximagesink); - ximagesink->running = TRUE; - ximagesink->event_thread = g_thread_create ( - (GThreadFunc) gst_ximagesink_event_thread, ximagesink, TRUE, NULL); - GST_OBJECT_UNLOCK (ximagesink); - - return xcontext; -} - -/* This function cleans the X context. Closing the Display and unrefing the - caps for supported formats. */ -static void -gst_ximagesink_xcontext_clear (GstXImageSink * ximagesink) -{ - GstXContext *xcontext; - - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - GST_OBJECT_LOCK (ximagesink); - if (ximagesink->xcontext == NULL) { - GST_OBJECT_UNLOCK (ximagesink); - return; - } - - /* Take the xcontext reference and NULL it while we - * clean it up, so that any buffer-alloced buffers - * arriving after this will be freed correctly */ - xcontext = ximagesink->xcontext; - ximagesink->xcontext = NULL; - - GST_OBJECT_UNLOCK (ximagesink); - - gst_caps_unref (xcontext->caps); - g_free (xcontext->par); - g_free (ximagesink->par); - ximagesink->par = NULL; - - g_mutex_lock (ximagesink->x_lock); - - XCloseDisplay (xcontext->disp); - - g_mutex_unlock (ximagesink->x_lock); - - g_free (xcontext); -} - -static void -gst_ximagesink_bufferpool_clear (GstXImageSink * ximagesink) -{ - - g_mutex_lock (ximagesink->pool_lock); - - while (ximagesink->buffer_pool) { - GstXImageBuffer *ximage = ximagesink->buffer_pool->data; - - ximagesink->buffer_pool = g_slist_delete_link (ximagesink->buffer_pool, - ximagesink->buffer_pool); - gst_ximage_buffer_free (ximage); - } - - g_mutex_unlock (ximagesink->pool_lock); -} - -/* Element stuff */ - -static GstCaps * -gst_ximagesink_getcaps (GstBaseSink * bsink) -{ - GstXImageSink *ximagesink; - GstCaps *caps; - int i; - - ximagesink = GST_XIMAGESINK (bsink); - - if (ximagesink->xcontext) - return gst_caps_ref (ximagesink->xcontext->caps); - - /* get a template copy and add the pixel aspect ratio */ - caps = - gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK (ximagesink)-> - sinkpad)); - for (i = 0; i < gst_caps_get_size (caps); ++i) { - GstStructure *structure = gst_caps_get_structure (caps, i); - - if (ximagesink->par) { - int nom, den; - - nom = gst_value_get_fraction_numerator (ximagesink->par); - den = gst_value_get_fraction_denominator (ximagesink->par); - gst_structure_set (structure, "pixel-aspect-ratio", - GST_TYPE_FRACTION, nom, den, NULL); - } - } - - return caps; -} - -static gboolean -gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) -{ - GstXImageSink *ximagesink; - gboolean ret = TRUE; - GstStructure *structure; - GstCaps *intersection; - const GValue *par; - gint new_width, new_height; - const GValue *fps; - - ximagesink = GST_XIMAGESINK (bsink); - - if (!ximagesink->xcontext) - return FALSE; - - GST_DEBUG_OBJECT (ximagesink, - "sinkconnect possible caps %" GST_PTR_FORMAT " with given caps %" - GST_PTR_FORMAT, ximagesink->xcontext->caps, caps); - - /* We intersect those caps with our template to make sure they are correct */ - intersection = gst_caps_intersect (ximagesink->xcontext->caps, caps); - GST_DEBUG_OBJECT (ximagesink, "intersection returned %" GST_PTR_FORMAT, - intersection); - if (gst_caps_is_empty (intersection)) { - gst_caps_unref (intersection); - return FALSE; - } - - gst_caps_unref (intersection); - - structure = gst_caps_get_structure (caps, 0); - - ret &= gst_structure_get_int (structure, "width", &new_width); - ret &= gst_structure_get_int (structure, "height", &new_height); - fps = gst_structure_get_value (structure, "framerate"); - ret &= (fps != NULL); - if (!ret) - return FALSE; - - /* if the caps contain pixel-aspect-ratio, they have to match ours, - * otherwise linking should fail */ - par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - if (par) { - if (ximagesink->par) { - if (gst_value_compare (par, ximagesink->par) != GST_VALUE_EQUAL) { - goto wrong_aspect; - } - } else if (ximagesink->xcontext->par) { - if (gst_value_compare (par, ximagesink->xcontext->par) != GST_VALUE_EQUAL) { - goto wrong_aspect; - } - } - } - - GST_VIDEO_SINK_WIDTH (ximagesink) = new_width; - GST_VIDEO_SINK_HEIGHT (ximagesink) = new_height; - ximagesink->fps_n = gst_value_get_fraction_numerator (fps); - ximagesink->fps_d = gst_value_get_fraction_denominator (fps); - - /* Notify application to set xwindow id now */ - g_mutex_lock (ximagesink->flow_lock); - if (!ximagesink->xwindow) { - g_mutex_unlock (ximagesink->flow_lock); - gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (ximagesink)); - } else { - g_mutex_unlock (ximagesink->flow_lock); - } - - /* Creating our window and our image */ - if (GST_VIDEO_SINK_WIDTH (ximagesink) <= 0 || - GST_VIDEO_SINK_HEIGHT (ximagesink) <= 0) { - GST_ELEMENT_ERROR (ximagesink, CORE, NEGOTIATION, (NULL), - ("Invalid image size.")); - return FALSE; - } - - g_mutex_lock (ximagesink->flow_lock); - if (!ximagesink->xwindow) { - ximagesink->xwindow = gst_ximagesink_xwindow_new (ximagesink, - GST_VIDEO_SINK_WIDTH (ximagesink), GST_VIDEO_SINK_HEIGHT (ximagesink)); - } - g_mutex_unlock (ximagesink->flow_lock); - - /* If our ximage has changed we destroy it, next chain iteration will create - a new one */ - if ((ximagesink->ximage) && - ((GST_VIDEO_SINK_WIDTH (ximagesink) != ximagesink->ximage->width) || - (GST_VIDEO_SINK_HEIGHT (ximagesink) != ximagesink->ximage->height))) { - GST_DEBUG_OBJECT (ximagesink, "our image is not usable anymore, unref %p", - ximagesink->ximage); - gst_buffer_unref (GST_BUFFER_CAST (ximagesink->ximage)); - ximagesink->ximage = NULL; - } - - return TRUE; - - /* ERRORS */ -wrong_aspect: - { - GST_INFO_OBJECT (ximagesink, "pixel aspect ratio does not match"); - return FALSE; - } -} - -static GstStateChangeReturn -gst_ximagesink_change_state (GstElement * element, GstStateChange transition) -{ - GstXImageSink *ximagesink; - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstXContext *xcontext = NULL; - - ximagesink = GST_XIMAGESINK (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - - /* Initializing the XContext */ - if (ximagesink->xcontext == NULL) { - xcontext = gst_ximagesink_xcontext_get (ximagesink); - if (xcontext == NULL) { - ret = GST_STATE_CHANGE_FAILURE; - goto beach; - } - GST_OBJECT_LOCK (ximagesink); - if (xcontext) - ximagesink->xcontext = xcontext; - GST_OBJECT_UNLOCK (ximagesink); - } - - /* call XSynchronize with the current value of synchronous */ - GST_DEBUG_OBJECT (ximagesink, "XSynchronize called with %s", - ximagesink->synchronous ? "TRUE" : "FALSE"); - g_mutex_lock (ximagesink->x_lock); - XSynchronize (ximagesink->xcontext->disp, ximagesink->synchronous); - g_mutex_unlock (ximagesink->x_lock); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - g_mutex_lock (ximagesink->flow_lock); - if (ximagesink->xwindow) - gst_ximagesink_xwindow_clear (ximagesink, ximagesink->xwindow); - g_mutex_unlock (ximagesink->flow_lock); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - ximagesink->fps_n = 0; - ximagesink->fps_d = 1; - GST_VIDEO_SINK_WIDTH (ximagesink) = 0; - GST_VIDEO_SINK_HEIGHT (ximagesink) = 0; - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_ximagesink_reset (ximagesink); - break; - default: - break; - } - -beach: - return ret; -} - -static void -gst_ximagesink_get_times (GstBaseSink * bsink, GstBuffer * buf, - GstClockTime * start, GstClockTime * end) -{ - GstXImageSink *ximagesink; - - ximagesink = GST_XIMAGESINK (bsink); - - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - *start = GST_BUFFER_TIMESTAMP (buf); - if (GST_BUFFER_DURATION_IS_VALID (buf)) { - *end = *start + GST_BUFFER_DURATION (buf); - } else { - if (ximagesink->fps_n > 0) { - *end = *start + - gst_util_uint64_scale_int (GST_SECOND, ximagesink->fps_d, - ximagesink->fps_n); - } - } - } -} - -static GstFlowReturn -gst_ximagesink_show_frame (GstBaseSink * bsink, GstBuffer * buf) -{ - GstXImageSink *ximagesink; - - g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); - - ximagesink = GST_XIMAGESINK (bsink); - - /* If this buffer has been allocated using our buffer management we simply - put the ximage which is in the PRIVATE pointer */ - if (GST_IS_XIMAGE_BUFFER (buf)) { - GST_LOG_OBJECT (ximagesink, "buffer from our pool, writing directly"); - if (!gst_ximagesink_ximage_put (ximagesink, GST_XIMAGE_BUFFER (buf))) - goto no_window; - } else { - /* Else we have to copy the data into our private image, */ - /* if we have one... */ - GST_LOG_OBJECT (ximagesink, "normal buffer, copying from it"); - if (!ximagesink->ximage) { - GST_DEBUG_OBJECT (ximagesink, "creating our ximage"); - ximagesink->ximage = gst_ximagesink_ximage_new (ximagesink, - GST_BUFFER_CAPS (buf)); - if (!ximagesink->ximage) - /* The create method should have posted an informative error */ - goto no_ximage; - - if (ximagesink->ximage->size < GST_BUFFER_SIZE (buf)) { - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximagesink->ximage->width, ximagesink->ximage->height), - ("XServer allocated buffer size did not match input buffer")); - - gst_ximagesink_ximage_destroy (ximagesink, ximagesink->ximage); - ximagesink->ximage = NULL; - goto no_ximage; - } - } - memcpy (GST_BUFFER_DATA (ximagesink->ximage), GST_BUFFER_DATA (buf), - MIN (GST_BUFFER_SIZE (buf), ximagesink->ximage->size)); - if (!gst_ximagesink_ximage_put (ximagesink, ximagesink->ximage)) - goto no_window; - } - - return GST_FLOW_OK; - - /* ERRORS */ -no_ximage: - { - /* No image available. That's very bad ! */ - GST_DEBUG ("could not create image"); - return GST_FLOW_ERROR; - } -no_window: - { - /* No Window available to put our image into */ - GST_WARNING_OBJECT (ximagesink, "could not output image - no window"); - return GST_FLOW_ERROR; - } -} - -/* Buffer management - * - * The buffer_alloc function must either return a buffer with given size and - * caps or create a buffer with different caps attached to the buffer. This - * last option is called reverse negotiation, ie, where the sink suggests a - * different format from the upstream peer. - * - * We try to do reverse negotiation when our geometry changes and we like a - * resized buffer. - */ -static GstFlowReturn -gst_ximagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buf) -{ - GstXImageSink *ximagesink; - GstXImageBuffer *ximage = NULL; - GstStructure *structure = NULL; - GstFlowReturn ret = GST_FLOW_OK; - GstCaps *alloc_caps; - gboolean alloc_unref = FALSE; - gint width, height; - - ximagesink = GST_XIMAGESINK (bsink); - - GST_LOG_OBJECT (ximagesink, - "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT - " and offset %" G_GUINT64_FORMAT, size, caps, offset); - - /* assume we're going to alloc what was requested, keep track of - * wheter we need to unref or not. When we suggest a new format - * upstream we will create a new caps that we need to unref. */ - alloc_caps = caps; - alloc_unref = FALSE; - - /* get struct to see what is requested */ - structure = gst_caps_get_structure (caps, 0); - - if (gst_structure_get_int (structure, "width", &width) && - gst_structure_get_int (structure, "height", &height)) { - GstVideoRectangle dst, src, result; - - src.w = width; - src.h = height; - - /* We take the flow_lock because the window might go away */ - g_mutex_lock (ximagesink->flow_lock); - if (!ximagesink->xwindow) { - g_mutex_unlock (ximagesink->flow_lock); - goto alloc; - } - - /* What is our geometry */ - gst_ximagesink_xwindow_update_geometry (ximagesink, ximagesink->xwindow); - dst.w = ximagesink->xwindow->width; - dst.h = ximagesink->xwindow->height; - - g_mutex_unlock (ximagesink->flow_lock); - - if (ximagesink->keep_aspect) { - GST_LOG_OBJECT (ximagesink, "enforcing aspect ratio in reverse caps " - "negotiation"); - gst_video_sink_center_rect (src, dst, &result, TRUE); - } else { - GST_LOG_OBJECT (ximagesink, "trying to resize to window geometry " - "ignoring aspect ratio"); - result.x = result.y = 0; - result.w = dst.w; - result.h = dst.h; - } - - /* We would like another geometry */ - if (width != result.w || height != result.h) { - int nom, den; - GstCaps *desired_caps; - GstStructure *desired_struct; - - /* make a copy of the incomming caps to create the new - * suggestion. We can't use make_writable because we might - * then destroy the original caps which we still need when the - * peer does not accept the suggestion. */ - desired_caps = gst_caps_copy (caps); - desired_struct = gst_caps_get_structure (desired_caps, 0); - - GST_DEBUG ("we would love to receive a %dx%d video", result.w, result.h); - gst_structure_set (desired_struct, "width", G_TYPE_INT, result.w, NULL); - gst_structure_set (desired_struct, "height", G_TYPE_INT, result.h, NULL); - - /* PAR property overrides the X calculated one */ - if (ximagesink->par) { - nom = gst_value_get_fraction_numerator (ximagesink->par); - den = gst_value_get_fraction_denominator (ximagesink->par); - gst_structure_set (desired_struct, "pixel-aspect-ratio", - GST_TYPE_FRACTION, nom, den, NULL); - } else if (ximagesink->xcontext->par) { - nom = gst_value_get_fraction_numerator (ximagesink->xcontext->par); - den = gst_value_get_fraction_denominator (ximagesink->xcontext->par); - gst_structure_set (desired_struct, "pixel-aspect-ratio", - GST_TYPE_FRACTION, nom, den, NULL); - } - - /* see if peer accepts our new suggestion, if there is no peer, this - * function returns true. */ - if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (ximagesink), - desired_caps)) { - gint bpp; - - bpp = size / height / width; - /* we will not alloc a buffer of the new suggested caps. Make sure - * we also unref this new caps after we set it on the buffer. */ - alloc_caps = desired_caps; - alloc_unref = TRUE; - width = result.w; - height = result.h; - size = bpp * width * height; - GST_DEBUG ("peer pad accepts our desired caps %" GST_PTR_FORMAT - " buffer size is now %d bytes", desired_caps, size); - } else { - GST_DEBUG ("peer pad does not accept our desired caps %" GST_PTR_FORMAT, - desired_caps); - /* we alloc a buffer with the original incomming caps */ - width = GST_VIDEO_SINK_WIDTH (ximagesink); - height = GST_VIDEO_SINK_HEIGHT (ximagesink); - } - } - } - -alloc: - /* Inspect our buffer pool */ - g_mutex_lock (ximagesink->pool_lock); - while (ximagesink->buffer_pool) { - ximage = (GstXImageBuffer *) ximagesink->buffer_pool->data; - - if (ximage) { - /* Removing from the pool */ - ximagesink->buffer_pool = g_slist_delete_link (ximagesink->buffer_pool, - ximagesink->buffer_pool); - - /* If the ximage is invalid for our need, destroy */ - if ((ximage->width != width) || (ximage->height != height)) { - gst_ximage_buffer_free (ximage); - ximage = NULL; - } else { - /* We found a suitable ximage */ - break; - } - } - } - g_mutex_unlock (ximagesink->pool_lock); - - /* We haven't found anything, creating a new one */ - if (!ximage) { - ximage = gst_ximagesink_ximage_new (ximagesink, alloc_caps); - } - /* Now we should have a ximage, set appropriate caps on it */ - if (ximage) { - gst_buffer_set_caps (GST_BUFFER_CAST (ximage), alloc_caps); - } - - /* could be our new reffed suggestion or the original unreffed caps */ - if (alloc_unref) - gst_caps_unref (alloc_caps); - - *buf = GST_BUFFER_CAST (ximage); - - return ret; -} - -/* Interfaces stuff */ - -static gboolean -gst_ximagesink_interface_supported (GstImplementsInterface * iface, GType type) -{ - g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY); - return TRUE; -} - -static void -gst_ximagesink_interface_init (GstImplementsInterfaceClass * klass) -{ - klass->supported = gst_ximagesink_interface_supported; -} - -static void -gst_ximagesink_navigation_send_event (GstNavigation * navigation, - GstStructure * structure) -{ - GstXImageSink *ximagesink = GST_XIMAGESINK (navigation); - GstEvent *event; - gint x_offset, y_offset; - gdouble x, y; - GstPad *pad = NULL; - - event = gst_event_new_navigation (structure); - - /* We are not converting the pointer coordinates as there's no hardware - scaling done here. The only possible scaling is done by videoscale and - videoscale will have to catch those events and tranform the coordinates - to match the applied scaling. So here we just add the offset if the image - is centered in the window. */ - - /* We take the flow_lock while we look at the window */ - g_mutex_lock (ximagesink->flow_lock); - - if (!ximagesink->xwindow) { - g_mutex_unlock (ximagesink->flow_lock); - return; - } - - x_offset = ximagesink->xwindow->width - GST_VIDEO_SINK_WIDTH (ximagesink); - y_offset = ximagesink->xwindow->height - GST_VIDEO_SINK_HEIGHT (ximagesink); - - g_mutex_unlock (ximagesink->flow_lock); - - if (gst_structure_get_double (structure, "pointer_x", &x)) { - x -= x_offset / 2; - gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x, NULL); - } - if (gst_structure_get_double (structure, "pointer_y", &y)) { - y -= y_offset / 2; - gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, y, NULL); - } - - pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (ximagesink)); - - if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) { - gst_pad_send_event (pad, event); - - gst_object_unref (pad); - } -} - -static void -gst_ximagesink_navigation_init (GstNavigationInterface * iface) -{ - iface->send_event = gst_ximagesink_navigation_send_event; -} - -static void -gst_ximagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) -{ - GstXImageSink *ximagesink = GST_XIMAGESINK (overlay); - GstXWindow *xwindow = NULL; - XWindowAttributes attr; - - /* We acquire the stream lock while setting this window in the element. - We are basically cleaning tons of stuff replacing the old window, putting - images while we do that would surely crash */ - g_mutex_lock (ximagesink->flow_lock); - - /* If we already use that window return */ - if (ximagesink->xwindow && (xwindow_id == ximagesink->xwindow->win)) { - g_mutex_unlock (ximagesink->flow_lock); - return; - } - - /* If the element has not initialized the X11 context try to do so */ - if (!ximagesink->xcontext && - !(ximagesink->xcontext = gst_ximagesink_xcontext_get (ximagesink))) { - g_mutex_unlock (ximagesink->flow_lock); - /* we have thrown a GST_ELEMENT_ERROR now */ - return; - } - - /* If a window is there already we destroy it */ - if (ximagesink->xwindow) { - gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow); - ximagesink->xwindow = NULL; - } - - /* If the xid is 0 we go back to an internal window */ - if (xwindow_id == 0) { - /* If no width/height caps nego did not happen window will be created - during caps nego then */ - if (GST_VIDEO_SINK_WIDTH (ximagesink) && GST_VIDEO_SINK_HEIGHT (ximagesink)) { - xwindow = gst_ximagesink_xwindow_new (ximagesink, - GST_VIDEO_SINK_WIDTH (ximagesink), - GST_VIDEO_SINK_HEIGHT (ximagesink)); - } - } else { - xwindow = g_new0 (GstXWindow, 1); - - xwindow->win = xwindow_id; - - /* We get window geometry, set the event we want to receive, - and create a GC */ - g_mutex_lock (ximagesink->x_lock); - XGetWindowAttributes (ximagesink->xcontext->disp, xwindow->win, &attr); - xwindow->width = attr.width; - xwindow->height = attr.height; - xwindow->internal = FALSE; - if (ximagesink->handle_events) { - XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask); - } - - xwindow->gc = XCreateGC (ximagesink->xcontext->disp, xwindow->win, 0, NULL); - g_mutex_unlock (ximagesink->x_lock); - } - - if (xwindow) - ximagesink->xwindow = xwindow; - - g_mutex_unlock (ximagesink->flow_lock); -} - -static void -gst_ximagesink_expose (GstXOverlay * overlay) -{ - GstXImageSink *ximagesink = GST_XIMAGESINK (overlay); - - gst_ximagesink_ximage_put (ximagesink, NULL); -} - -static void -gst_ximagesink_set_event_handling (GstXOverlay * overlay, - gboolean handle_events) -{ - GstXImageSink *ximagesink = GST_XIMAGESINK (overlay); - - ximagesink->handle_events = handle_events; - - g_mutex_lock (ximagesink->flow_lock); - - if (G_UNLIKELY (!ximagesink->xwindow)) { - g_mutex_unlock (ximagesink->flow_lock); - return; - } - - g_mutex_lock (ximagesink->x_lock); - - if (handle_events) { - if (ximagesink->xwindow->internal) { - XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win, - ExposureMask | StructureNotifyMask | PointerMotionMask | - KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - } else { - XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win, - ExposureMask | StructureNotifyMask | PointerMotionMask | - KeyPressMask | KeyReleaseMask); - } - } else { - XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win, 0); - } - - g_mutex_unlock (ximagesink->x_lock); - - g_mutex_unlock (ximagesink->flow_lock); -} - -static void -gst_ximagesink_xoverlay_init (GstXOverlayClass * iface) -{ - iface->set_xwindow_id = gst_ximagesink_set_xwindow_id; - iface->expose = gst_ximagesink_expose; - iface->handle_events = gst_ximagesink_set_event_handling; -} - -/* =========================================== */ -/* */ -/* Init & Class init */ -/* */ -/* =========================================== */ - -static void -gst_ximagesink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstXImageSink *ximagesink; - - g_return_if_fail (GST_IS_XIMAGESINK (object)); - - ximagesink = GST_XIMAGESINK (object); - - switch (prop_id) { - case PROP_DISPLAY: - ximagesink->display_name = g_strdup (g_value_get_string (value)); - break; - case PROP_SYNCHRONOUS: - ximagesink->synchronous = g_value_get_boolean (value); - if (ximagesink->xcontext) { - GST_DEBUG_OBJECT (ximagesink, "XSynchronize called with %s", - ximagesink->synchronous ? "TRUE" : "FALSE"); - g_mutex_lock (ximagesink->x_lock); - XSynchronize (ximagesink->xcontext->disp, ximagesink->synchronous); - g_mutex_unlock (ximagesink->x_lock); - } - break; - case PROP_FORCE_ASPECT_RATIO: - ximagesink->keep_aspect = g_value_get_boolean (value); - break; - case PROP_PIXEL_ASPECT_RATIO: - { - GValue *tmp; - - tmp = g_new0 (GValue, 1); - g_value_init (tmp, GST_TYPE_FRACTION); - - if (!g_value_transform (value, tmp)) { - GST_WARNING_OBJECT (ximagesink, - "Could not transform string to aspect ratio"); - g_free (tmp); - } else { - GST_DEBUG_OBJECT (ximagesink, "set PAR to %d/%d", - gst_value_get_fraction_numerator (tmp), - gst_value_get_fraction_denominator (tmp)); - g_free (ximagesink->par); - ximagesink->par = tmp; - } - } - break; - case PROP_HANDLE_EVENTS: - gst_ximagesink_set_event_handling (GST_X_OVERLAY (ximagesink), - g_value_get_boolean (value)); - break; - case PROP_HANDLE_EXPOSE: - ximagesink->handle_expose = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_ximagesink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstXImageSink *ximagesink; - - g_return_if_fail (GST_IS_XIMAGESINK (object)); - - ximagesink = GST_XIMAGESINK (object); - - switch (prop_id) { - case PROP_DISPLAY: - g_value_set_string (value, ximagesink->display_name); - break; - case PROP_SYNCHRONOUS: - g_value_set_boolean (value, ximagesink->synchronous); - break; - case PROP_FORCE_ASPECT_RATIO: - g_value_set_boolean (value, ximagesink->keep_aspect); - break; - case PROP_PIXEL_ASPECT_RATIO: - if (ximagesink->par) - g_value_transform (ximagesink->par, value); - break; - case PROP_HANDLE_EVENTS: - g_value_set_boolean (value, ximagesink->handle_events); - break; - case PROP_HANDLE_EXPOSE: - g_value_set_boolean (value, ximagesink->handle_expose); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_ximagesink_reset (GstXImageSink * ximagesink) -{ - GThread *thread; - - GST_OBJECT_LOCK (ximagesink); - ximagesink->running = FALSE; - /* grab thread and mark it as NULL */ - thread = ximagesink->event_thread; - ximagesink->event_thread = NULL; - GST_OBJECT_UNLOCK (ximagesink); - - /* Wait for our event thread to finish before we clean up our stuff. */ - if (thread) - g_thread_join (thread); - - if (ximagesink->ximage) { - gst_buffer_unref (ximagesink->ximage); - ximagesink->ximage = NULL; - } - if (ximagesink->cur_image) { - gst_buffer_unref (ximagesink->cur_image); - ximagesink->cur_image = NULL; - } - - gst_ximagesink_bufferpool_clear (ximagesink); - - g_mutex_lock (ximagesink->flow_lock); - if (ximagesink->xwindow) { - gst_ximagesink_xwindow_clear (ximagesink, ximagesink->xwindow); - gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow); - ximagesink->xwindow = NULL; - } - g_mutex_unlock (ximagesink->flow_lock); - - gst_ximagesink_xcontext_clear (ximagesink); -} - -static void -gst_ximagesink_finalize (GObject * object) -{ - GstXImageSink *ximagesink; - - ximagesink = GST_XIMAGESINK (object); - - gst_ximagesink_reset (ximagesink); - - if (ximagesink->display_name) { - g_free (ximagesink->display_name); - ximagesink->display_name = NULL; - } - if (ximagesink->par) { - g_free (ximagesink->par); - ximagesink->par = NULL; - } - if (ximagesink->x_lock) { - g_mutex_free (ximagesink->x_lock); - ximagesink->x_lock = NULL; - } - if (ximagesink->flow_lock) { - g_mutex_free (ximagesink->flow_lock); - ximagesink->flow_lock = NULL; - } - if (ximagesink->pool_lock) { - g_mutex_free (ximagesink->pool_lock); - ximagesink->pool_lock = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_ximagesink_init (GstXImageSink * ximagesink) -{ - ximagesink->display_name = NULL; - ximagesink->xcontext = NULL; - ximagesink->xwindow = NULL; - ximagesink->ximage = NULL; - ximagesink->cur_image = NULL; - - ximagesink->event_thread = NULL; - ximagesink->running = FALSE; - - ximagesink->fps_n = 0; - ximagesink->fps_d = 1; - - ximagesink->x_lock = g_mutex_new (); - ximagesink->flow_lock = g_mutex_new (); - - ximagesink->par = NULL; - - ximagesink->pool_lock = g_mutex_new (); - ximagesink->buffer_pool = NULL; - - ximagesink->synchronous = FALSE; - ximagesink->keep_aspect = FALSE; - ximagesink->handle_events = TRUE; - ximagesink->handle_expose = TRUE; -} - -static void -gst_ximagesink_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_ximagesink_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_ximagesink_sink_template_factory)); -} - -static void -gst_ximagesink_class_init (GstXImageSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = gst_ximagesink_finalize; - gobject_class->set_property = gst_ximagesink_set_property; - gobject_class->get_property = gst_ximagesink_get_property; - - g_object_class_install_property (gobject_class, PROP_DISPLAY, - g_param_spec_string ("display", "Display", "X Display name", - NULL, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS, - g_param_spec_boolean ("synchronous", "Synchronous", "When enabled, runs " - "the X display in synchronous mode. (used only for debugging)", FALSE, - G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO, - g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio", - "When enabled, reverse caps negotiation (scaling) will respect " - "original aspect ratio", FALSE, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO, - g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio", - "The pixel aspect ratio of the device", "1/1", G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS, - g_param_spec_boolean ("handle-events", "Handle XEvents", - "When enabled, XEvents will be selected and handled", TRUE, - G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE, - g_param_spec_boolean ("handle-expose", "Handle expose", "When enabled, " - "the current frame will always be drawn in response to X Expose " - "events", TRUE, G_PARAM_READWRITE)); - - gstelement_class->change_state = gst_ximagesink_change_state; - - gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_ximagesink_getcaps); - gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_ximagesink_setcaps); - gstbasesink_class->buffer_alloc = - GST_DEBUG_FUNCPTR (gst_ximagesink_buffer_alloc); - gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_ximagesink_get_times); - gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_ximagesink_show_frame); - gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_ximagesink_show_frame); -} - -/* ============================================================= */ -/* */ -/* Public Methods */ -/* */ -/* ============================================================= */ - -/* =========================================== */ -/* */ -/* Object typing & Creation */ -/* */ -/* =========================================== */ - -GType -gst_ximagesink_get_type (void) -{ - static GType ximagesink_type = 0; - - if (!ximagesink_type) { - static const GTypeInfo ximagesink_info = { - sizeof (GstXImageSinkClass), - gst_ximagesink_base_init, - NULL, - (GClassInitFunc) gst_ximagesink_class_init, - NULL, - NULL, - sizeof (GstXImageSink), - 0, - (GInstanceInitFunc) gst_ximagesink_init, - }; - static const GInterfaceInfo iface_info = { - (GInterfaceInitFunc) gst_ximagesink_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo navigation_info = { - (GInterfaceInitFunc) gst_ximagesink_navigation_init, - NULL, - NULL, - }; - static const GInterfaceInfo overlay_info = { - (GInterfaceInitFunc) gst_ximagesink_xoverlay_init, - NULL, - NULL, - }; - - ximagesink_type = g_type_register_static (GST_TYPE_VIDEO_SINK, - "GstXImageSink", &ximagesink_info, 0); - - g_type_add_interface_static (ximagesink_type, GST_TYPE_IMPLEMENTS_INTERFACE, - &iface_info); - g_type_add_interface_static (ximagesink_type, GST_TYPE_NAVIGATION, - &navigation_info); - g_type_add_interface_static (ximagesink_type, GST_TYPE_X_OVERLAY, - &overlay_info); - - /* register type and create class in a more safe place instead of at - * runtime since the type registration and class creation is not - * threadsafe. */ - g_type_class_ref (gst_ximage_buffer_get_type ()); - } - - return ximagesink_type; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/ximage/ximagesink.h --- a/gst_plugins_base/sys/ximage/ximagesink.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Julien Moutte - * - * 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. - */ - -#ifndef __GST_XIMAGESINK_H__ -#define __GST_XIMAGESINK_H__ - -#include - -#ifdef HAVE_XSHM -#include -#include -#include -#endif /* HAVE_XSHM */ - -#include -#include - -#ifdef HAVE_XSHM -#include -#endif /* HAVE_XSHM */ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_XIMAGESINK \ - (gst_ximagesink_get_type()) -#define GST_XIMAGESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_XIMAGESINK, GstXImageSink)) -#define GST_XIMAGESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_XIMAGESINK, GstXImageSinkClass)) -#define GST_IS_XIMAGESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XIMAGESINK)) -#define GST_IS_XIMAGESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XIMAGESINK)) - -typedef struct _GstXContext GstXContext; -typedef struct _GstXWindow GstXWindow; - -typedef struct _GstXImageBuffer GstXImageBuffer; -typedef struct _GstXImageBufferClass GstXImageBufferClass; - -typedef struct _GstXImageSink GstXImageSink; -typedef struct _GstXImageSinkClass GstXImageSinkClass; - -/** - * GstXContext: - * @disp: the X11 Display of this context - * @screen: the default Screen of Display @disp - * @screen_num: the Screen number of @screen - * @visual: the default Visual of Screen @screen - * @root: the root Window of Display @disp - * @white: the value of a white pixel on Screen @screen - * @black: the value of a black pixel on Screen @screen - * @depth: the color depth of Display @disp - * @bpp: the number of bits per pixel on Display @disp - * @endianness: the endianness of image bytes on Display @disp - * @width: the width in pixels of Display @disp - * @height: the height in pixels of Display @disp - * @widthmm: the width in millimeters of Display @disp - * @heightmm: the height in millimeters of Display @disp - * @par: the pixel aspect ratio calculated from @width, @widthmm and @height, - * @heightmm ratio - * @use_xshm: used to known wether of not XShm extension is usable or not even - * if the Extension is present - * @caps: the #GstCaps that Display @disp can accept - * - * Structure used to store various informations collected/calculated for a - * Display. - */ -struct _GstXContext { - Display *disp; - - Screen *screen; - gint screen_num; - - Visual *visual; - - Window root; - - gulong white, black; - - gint depth; - gint bpp; - gint endianness; - - gint width, height; - gint widthmm, heightmm; - GValue *par; /* calculated pixel aspect ratio */ - - gboolean use_xshm; - - GstCaps *caps; -}; - -/** - * GstXWindow: - * @win: the Window ID of this X11 window - * @width: the width in pixels of Window @win - * @height: the height in pixels of Window @win - * @internal: used to remember if Window @win was created internally or passed - * through the #GstXOverlay interface - * @gc: the Graphical Context of Window @win - * - * Structure used to store informations about a Window. - */ -struct _GstXWindow { - Window win; - gint width, height; - gboolean internal; - GC gc; -}; - -/** - * GstXImageBuffer: - * @ximagesink: a reference to our #GstXImageSink - * @ximage: the XImage of this buffer - * @width: the width in pixels of XImage @ximage - * @height: the height in pixels of XImage @ximage - * @size: the size in bytes of XImage @ximage - * - * Subclass of #GstBuffer containing additional information about an XImage. - */ -struct _GstXImageBuffer { - GstBuffer buffer; - - /* Reference to the ximagesink we belong to */ - GstXImageSink *ximagesink; - - XImage *ximage; - -#ifdef HAVE_XSHM - XShmSegmentInfo SHMInfo; -#endif /* HAVE_XSHM */ - - gint width, height; - size_t size; -}; - -/** - * GstXImageSink: - * @display_name: the name of the Display we want to render to - * @xcontext: our instance's #GstXContext - * @xwindow: the #GstXWindow we are rendering to - * @ximage: internal #GstXImage used to store incoming buffers and render when - * not using the buffer_alloc optimization mechanism - * @cur_image: a reference to the last #GstXImage that was put to @xwindow. It - * is used when Expose events are received to redraw the latest video frame - * @event_thread: a thread listening for events on @xwindow and handling them - * @running: used to inform @event_thread if it should run/shutdown - * @fps_n: the framerate fraction numerator - * @fps_d: the framerate fraction denominator - * @x_lock: used to protect X calls as we are not using the XLib in threaded - * mode - * @flow_lock: used to protect data flow routines from external calls such as - * events from @event_thread or methods from the #GstXOverlay interface - * @par: used to override calculated pixel aspect ratio from @xcontext - * @pool_lock: used to protect the buffer pool - * @buffer_pool: a list of #GstXImageBuffer that could be reused at next buffer - * allocation call - * @synchronous: used to store if XSynchronous should be used or not (for - * debugging purpose only) - * @keep_aspect: used to remember if reverse negotiation scaling should respect - * aspect ratio - * @handle_events: used to know if we should handle select XEvents or not - * - * The #GstXImageSink data structure. - */ -struct _GstXImageSink { - /* Our element stuff */ - GstVideoSink videosink; - - char *display_name; - - GstXContext *xcontext; - GstXWindow *xwindow; - GstXImageBuffer *ximage; - GstXImageBuffer *cur_image; - - GThread *event_thread; - gboolean running; - - /* Framerate numerator and denominator */ - gint fps_n; - gint fps_d; - - GMutex *x_lock; - GMutex *flow_lock; - - /* object-set pixel aspect ratio */ - GValue *par; - - GMutex *pool_lock; - GSList *buffer_pool; - - gboolean synchronous; - gboolean keep_aspect; - gboolean handle_events; - gboolean handle_expose; -}; - -struct _GstXImageSinkClass { - GstVideoSinkClass parent_class; -}; - -GType gst_ximagesink_get_type(void); - -G_END_DECLS - -#endif /* __GST_XIMAGESINK_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/xvimage/xvimagesink.c --- a/gst_plugins_base/sys/xvimage/xvimagesink.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3254 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Julien Moutte - * - * 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. - */ - -/** - * SECTION:element-xvimagesink - * - * - * - * XvImageSink renders video frames to a drawable (XWindow) on a local display - * using the XVideo extension. Rendering to a remote display is theorically - * possible but i doubt that the XVideo extension is actually available when - * connecting to a remote display. This element can receive a Window ID from the - * application through the XOverlay interface and will then render video frames - * in this drawable. If no Window ID was provided by the application, the - * element will create its own internal window and render into it. - * - * Scaling - * - * The XVideo extension, when it's available, handles hardware accelerated - * scaling of video frames. This means that the element will just accept - * incoming video frames no matter their geometry and will then put them to the - * drawable scaling them on the fly. Using the - * force-aspect-ratio - * property it is possible to enforce scaling with a constant aspect ratio, - * which means drawing black borders around the video frame. - * - * Events - * - * XvImageSink creates a thread to handle events coming from the drawable. There - * are several kind of events that can be grouped in 2 big categories: input - * events and window state related events. Input events will be translated to - * navigation events and pushed upstream for other elements to react on them. - * This includes events such as pointer moves, key press/release, clicks etc... - * Other events are used to handle the drawable appearance even when the data - * is not flowing (GST_STATE_PAUSED). That means that even when the element is - * paused, it will receive expose events from the drawable and draw the latest - * frame with correct borders/aspect-ratio. - * - * Pixel aspect ratio - * - * When changing state to GST_STATE_READY, XvImageSink will open a connection to - * the display specified in the - * display property or the - * default display if nothing specified. Once this connection is open it will - * inspect the display configuration including the physical display geometry and - * then calculate the pixel aspect ratio. When receiving video frames with a - * different pixel aspect ratio, XvImageSink will use hardware scaling to - * display the video frames correctly on display's pixel aspect ratio. - * Sometimes the calculated pixel aspect ratio can be wrong, it is - * then possible to enforce a specific pixel aspect ratio using the - * pixel-aspect-ratio - * property. - * - * Examples - * - * Here is a simple pipeline to test hardware scaling : - * - * gst-launch -v videotestsrc ! xvimagesink - * - * When the test video signal appears you can resize the window and see that - * video frames are scaled through hardware (no extra CPU cost). You can try - * again setting the force-aspect-ratio property to true and observe the borders - * drawn around the scaled image respecting aspect ratio. - * - * gst-launch -v videotestsrc ! xvimagesink force-aspect-ratio=true - * - * - * - * Here is a simple pipeline to test navigation events : - * - * gst-launch -v videotestsrc ! navigationtest ! xvimagesink - * - * While moving the mouse pointer over the test signal you will see a black box - * following the mouse pointer. If you press the mouse button somewhere on the - * video and release it somewhere else a green box will appear where you pressed - * the button and a red one where you released it. (The navigationtest element - * is part of gst-plugins-good.) You can observe here that even if the images - * are scaled through hardware the pointer coordinates are converted back to the - * original video frame geometry so that the box can be drawn to the correct - * position. This also handles borders correctly, limiting coordinates to the - * image area - * - * - * Here is a simple pipeline to test pixel aspect ratio : - * - * gst-launch -v videotestsrc ! video/x-raw-yuv, pixel-aspect-ratio=(fraction)4/3 ! xvimagesink - * - * This is faking a 4/3 pixel aspect ratio caps on video frames produced by - * videotestsrc, in most cases the pixel aspect ratio of the display will be - * 1/1. This means that XvImageSink will have to do the scaling to convert - * incoming frames to a size that will match the display pixel aspect ratio - * (from 320x240 to 320x180 in this case). Note that you might have to escape - * some characters for your shell like '\(fraction\)'. - * - * - * Here is a test pipeline to test the colorbalance interface : - * - * gst-launch -v videotestsrc ! xvimagesink hue=100 saturation=-100 brightness=100 - * - * - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* Our interfaces */ -#include -#include -#include -#include -/* Helper functions */ -#include - -/* Object header */ -#include "xvimagesink.h" - -/* Debugging category */ -#include -GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink); -#define GST_CAT_DEFAULT gst_debug_xvimagesink - -typedef struct -{ - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long input_mode; - unsigned long status; -} -MotifWmHints, MwmHints; - -#define MWM_HINTS_DECORATIONS (1L << 1) - -static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink); - -static GstBufferClass *xvimage_buffer_parent_class = NULL; -static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage); - -static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * - xvimagesink, GstXWindow * xwindow); -static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink, - GstCaps * caps); -static void gst_xvimagesink_expose (GstXOverlay * overlay); - -/* ElementFactory information */ -static const GstElementDetails gst_xvimagesink_details = -GST_ELEMENT_DETAILS ("Video sink", - "Sink/Video", - "A Xv based videosink", - "Julien Moutte "); - -/* Default template - initiated with class struct to allow gst-register to work - without X running */ -static GstStaticPadTemplate gst_xvimagesink_sink_template_factory = - GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw-rgb, " - "framerate = (fraction) [ 0, MAX ], " - "width = (int) [ 1, MAX ], " - "height = (int) [ 1, MAX ]; " - "video/x-raw-yuv, " - "framerate = (fraction) [ 0, MAX ], " - "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]") - ); - -enum -{ - ARG_0, - ARG_CONTRAST, - ARG_BRIGHTNESS, - ARG_HUE, - ARG_SATURATION, - ARG_DISPLAY, - ARG_SYNCHRONOUS, - ARG_PIXEL_ASPECT_RATIO, - ARG_FORCE_ASPECT_RATIO, - ARG_HANDLE_EVENTS, - ARG_DEVICE, - ARG_DEVICE_NAME, - ARG_HANDLE_EXPOSE, - ARG_DOUBLE_BUFFER -}; - -static GstVideoSinkClass *parent_class = NULL; - -/* ============================================================= */ -/* */ -/* Private Methods */ -/* */ -/* ============================================================= */ - -/* xvimage buffers */ - -#define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type()) - -#define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER)) -#define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer)) - -/* This function destroys a GstXvImage handling XShm availability */ -static void -gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage) -{ - GstXvImageSink *xvimagesink; - - GST_DEBUG_OBJECT (xvimage, "Destroying buffer"); - - xvimagesink = xvimage->xvimagesink; - if (G_UNLIKELY (xvimagesink == NULL)) - goto no_sink; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - GST_OBJECT_LOCK (xvimagesink); - - /* If the destroyed image is the current one we destroy our reference too */ - if (xvimagesink->cur_image == xvimage) - xvimagesink->cur_image = NULL; - - /* We might have some buffers destroyed after changing state to NULL */ - if (xvimagesink->xcontext == NULL) { - GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext"); -#ifdef HAVE_XSHM - /* Need to free the shared memory segment even if the x context - * was already cleaned up */ - if (xvimage->SHMInfo.shmaddr != ((void *) -1)) { - shmdt (xvimage->SHMInfo.shmaddr); - } -#endif - goto beach; - } - - g_mutex_lock (xvimagesink->x_lock); - -#ifdef HAVE_XSHM - if (xvimagesink->xcontext->use_xshm) { - if (xvimage->SHMInfo.shmaddr != ((void *) -1)) { - GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx", - xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg); - XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo); - XSync (xvimagesink->xcontext->disp, FALSE); - - shmdt (xvimage->SHMInfo.shmaddr); - } - if (xvimage->xvimage) - XFree (xvimage->xvimage); - } else -#endif /* HAVE_XSHM */ - { - if (xvimage->xvimage) { - if (xvimage->xvimage->data) { - g_free (xvimage->xvimage->data); - } - XFree (xvimage->xvimage); - } - } - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); - -beach: - GST_OBJECT_UNLOCK (xvimagesink); - xvimage->xvimagesink = NULL; - gst_object_unref (xvimagesink); - - GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)-> - finalize (GST_MINI_OBJECT (xvimage)); - - return; - -no_sink: - { - GST_WARNING ("no sink found"); - return; - } -} - -static void -gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage) -{ - GstXvImageSink *xvimagesink; - gboolean running; - - xvimagesink = xvimage->xvimagesink; - if (G_UNLIKELY (xvimagesink == NULL)) - goto no_sink; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - GST_OBJECT_LOCK (xvimagesink); - running = xvimagesink->running; - GST_OBJECT_UNLOCK (xvimagesink); - - /* If our geometry changed we can't reuse that image. */ - if (running == FALSE) { - GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down"); - gst_xvimage_buffer_destroy (xvimage); - } else if ((xvimage->width != xvimagesink->video_width) || - (xvimage->height != xvimagesink->video_height)) { - GST_LOG_OBJECT (xvimage, - "destroy image as its size changed %dx%d vs current %dx%d", - xvimage->width, xvimage->height, - xvimagesink->video_width, xvimagesink->video_height); - gst_xvimage_buffer_destroy (xvimage); - } else { - /* In that case we can reuse the image and add it to our image pool. */ - GST_LOG_OBJECT (xvimage, "recycling image in pool"); - /* need to increment the refcount again to recycle */ - gst_buffer_ref (GST_BUFFER (xvimage)); - g_mutex_lock (xvimagesink->pool_lock); - xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool, - xvimage); - g_mutex_unlock (xvimagesink->pool_lock); - } - return; - -no_sink: - { - GST_WARNING ("no sink found"); - return; - } -} - -static void -gst_xvimage_buffer_free (GstXvImageBuffer * xvimage) -{ - /* make sure it is not recycled */ - xvimage->width = -1; - xvimage->height = -1; - gst_buffer_unref (GST_BUFFER (xvimage)); -} - -static void -gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class) -{ -#ifdef HAVE_XSHM - xvimage->SHMInfo.shmaddr = ((void *) -1); - xvimage->SHMInfo.shmid = -1; -#endif -} - -static void -gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data) -{ - GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); - - xvimage_buffer_parent_class = g_type_class_peek_parent (g_class); - - mini_object_class->finalize = (GstMiniObjectFinalizeFunction) - gst_xvimage_buffer_finalize; -} - -static GType -gst_xvimage_buffer_get_type (void) -{ - static GType _gst_xvimage_buffer_type; - - if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) { - static const GTypeInfo xvimage_buffer_info = { - sizeof (GstBufferClass), - NULL, - NULL, - gst_xvimage_buffer_class_init, - NULL, - NULL, - sizeof (GstXvImageBuffer), - 0, - (GInstanceInitFunc) gst_xvimage_buffer_init, - NULL - }; - _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER, - "GstXvImageBuffer", &xvimage_buffer_info, 0); - } - return _gst_xvimage_buffer_type; -} - -/* X11 stuff */ - -static gboolean error_caught = FALSE; - -static int -gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent) -{ - char error_msg[1024]; - - XGetErrorText (display, xevent->error_code, error_msg, 1024); - GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg); - error_caught = TRUE; - return 0; -} - -#ifdef HAVE_XSHM -/* This function checks that it is actually really possible to create an image - using XShm */ -static gboolean -gst_xvimagesink_check_xshm_calls (GstXContext * xcontext) -{ - XvImage *xvimage; - XShmSegmentInfo SHMInfo; - gint size; - int (*handler) (Display *, XErrorEvent *); - gboolean result = FALSE; - gboolean did_attach = FALSE; - - g_return_val_if_fail (xcontext != NULL, FALSE); - - /* Sync to ensure any older errors are already processed */ - XSync (xcontext->disp, FALSE); - - /* Set defaults so we don't free these later unnecessarily */ - SHMInfo.shmaddr = ((void *) -1); - SHMInfo.shmid = -1; - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); - - /* Trying to create a 1x1 picture */ - GST_DEBUG ("XvShmCreateImage of 1x1"); - xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id, - xcontext->im_format, NULL, 1, 1, &SHMInfo); - - /* Might cause an error, sync to ensure it is noticed */ - XSync (xcontext->disp, FALSE); - if (!xvimage || error_caught) { - GST_WARNING ("could not XvShmCreateImage a 1x1 image"); - goto beach; - } - size = xvimage->data_size; - - SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); - if (SHMInfo.shmid == -1) { - GST_WARNING ("could not get shared memory of %d bytes", size); - goto beach; - } - - SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0); - if (SHMInfo.shmaddr == ((void *) -1)) { - GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); - /* Clean up the shared memory segment */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - /* Delete the shared memory segment as soon as we manage to attach. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - - xvimage->data = SHMInfo.shmaddr; - SHMInfo.readOnly = FALSE; - - if (XShmAttach (xcontext->disp, &SHMInfo) == 0) { - GST_WARNING ("Failed to XShmAttach"); - goto beach; - } - - /* Sync to ensure we see any errors we caused */ - XSync (xcontext->disp, FALSE); - - GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid, - SHMInfo.shmseg); - - if (!error_caught) { - did_attach = TRUE; - /* store whether we succeeded in result */ - result = TRUE; - } - -beach: - /* Sync to ensure we swallow any errors we caused and reset error_caught */ - XSync (xcontext->disp, FALSE); - - error_caught = FALSE; - XSetErrorHandler (handler); - - if (did_attach) { - GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx", - SHMInfo.shmid, SHMInfo.shmseg); - XShmDetach (xcontext->disp, &SHMInfo); - XSync (xcontext->disp, FALSE); - } - if (SHMInfo.shmaddr != ((void *) -1)) - shmdt (SHMInfo.shmaddr); - if (xvimage) - XFree (xvimage); - return result; -} -#endif /* HAVE_XSHM */ - -/* This function handles GstXvImage creation depending on XShm availability */ -static GstXvImageBuffer * -gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps) -{ - GstXvImageBuffer *xvimage = NULL; - GstStructure *structure = NULL; - gboolean succeeded = FALSE; - int (*handler) (Display *, XErrorEvent *); - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER); - GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer"); - - structure = gst_caps_get_structure (caps, 0); - - if (!gst_structure_get_int (structure, "width", &xvimage->width) || - !gst_structure_get_int (structure, "height", &xvimage->height)) { - GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps); - } - - GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width, - xvimage->height); - - xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps); - if (xvimage->im_format == -1) { - GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %" - GST_PTR_FORMAT, caps); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimage->width, xvimage->height), ("Invalid input caps")); - goto beach_unlocked; - } - xvimage->xvimagesink = gst_object_ref (xvimagesink); - - g_mutex_lock (xvimagesink->x_lock); - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); - -#ifdef HAVE_XSHM - if (xvimagesink->xcontext->use_xshm) { - int expected_size; - - xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimage->im_format, NULL, - xvimage->width, xvimage->height, &xvimage->SHMInfo); - if (!xvimage->xvimage || error_caught) { - g_mutex_unlock (xvimagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimage->width, xvimage->height), - ("could not XvShmCreateImage a %dx%d image", - xvimage->width, xvimage->height)); - goto beach_unlocked; - } - - /* we have to use the returned data_size for our shm size */ - xvimage->size = xvimage->xvimage->data_size; - GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT, - xvimage->size); - - /* calculate the expected size. This is only for sanity checking the - * number we get from X. */ - switch (xvimage->im_format) { - case GST_MAKE_FOURCC ('I', '4', '2', '0'): - expected_size = - GST_ROUND_UP_2 (xvimage->height) * GST_ROUND_UP_4 (xvimage->width); - expected_size += - GST_ROUND_UP_2 (xvimage->height) * GST_ROUND_UP_8 (xvimage->width) / - 2; - break; - case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): - case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): - case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): - expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2); - break; - default: - expected_size = 0; - break; - } - if (expected_size != 0 && xvimage->size != expected_size) { - GST_WARNING_OBJECT (xvimagesink, - "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)", - xvimage->size, expected_size); - } - - /* Be verbose about our XvImage stride */ - { - guint plane; - - for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) { - GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, " - "offset of %d", plane, xvimage->xvimage->pitches[plane], - xvimage->xvimage->offsets[plane]); - } - } - - xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size, - IPC_CREAT | 0777); - if (xvimage->SHMInfo.shmid == -1) { - g_mutex_unlock (xvimagesink->x_lock); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimage->width, xvimage->height), - ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", - xvimage->size)); - goto beach_unlocked; - } - - xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0); - if (xvimage->SHMInfo.shmaddr == ((void *) -1)) { - g_mutex_unlock (xvimagesink->x_lock); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimage->width, xvimage->height), - ("Failed to shmat: %s", g_strerror (errno))); - /* Clean up the shared memory segment */ - shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL); - goto beach_unlocked; - } - - /* Delete the shared memory segment as soon as we manage to attach. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL); - - xvimage->xvimage->data = xvimage->SHMInfo.shmaddr; - xvimage->SHMInfo.readOnly = FALSE; - - if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) { - g_mutex_unlock (xvimagesink->x_lock); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimage->width, xvimage->height), ("Failed to XShmAttach")); - goto beach_unlocked; - } - - XSync (xvimagesink->xcontext->disp, FALSE); - GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx", - xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg); - } else -#endif /* HAVE_XSHM */ - { - xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimage->im_format, NULL, xvimage->width, xvimage->height); - if (!xvimage->xvimage || error_caught) { - g_mutex_unlock (xvimagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create outputimage buffer of %dx%d pixels", - xvimage->width, xvimage->height), - ("could not XvCreateImage a %dx%d image", - xvimage->width, xvimage->height)); - goto beach_unlocked; - } - - /* we have to use the returned data_size for our image size */ - xvimage->size = xvimage->xvimage->data_size; - xvimage->xvimage->data = g_malloc (xvimage->size); - - XSync (xvimagesink->xcontext->disp, FALSE); - } - - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - - succeeded = TRUE; - - GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data; - GST_BUFFER_SIZE (xvimage) = xvimage->size; - - g_mutex_unlock (xvimagesink->x_lock); - -beach_unlocked: - if (!succeeded) { - gst_xvimage_buffer_free (xvimage); - xvimage = NULL; - } - - return xvimage; -} - -/* We are called with the x_lock taken */ -static void -gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink, - GstXWindow * xwindow, GstVideoRectangle rect) -{ - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - g_return_if_fail (xwindow != NULL); - - XSetForeground (xvimagesink->xcontext->disp, xwindow->gc, - xvimagesink->xcontext->black); - - /* Left border */ - if (rect.x > 0) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, rect.x, xwindow->height); - } - - /* Right border */ - if ((rect.x + rect.w) < xwindow->width) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - rect.x + rect.w, 0, xwindow->width, xwindow->height); - } - - /* Top border */ - if (rect.y > 0) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, xwindow->width, rect.y); - } - - /* Bottom border */ - if ((rect.y + rect.h) < xwindow->height) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, rect.y + rect.h, xwindow->width, xwindow->height); - } -} - -/* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE - * if no window was available */ -static gboolean -gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, - GstXvImageBuffer * xvimage) -{ - GstVideoRectangle src, dst, result; - gboolean draw_border = FALSE; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE); - - /* We take the flow_lock. If expose is in there we don't want to run - concurrently from the data flow thread */ - g_mutex_lock (xvimagesink->flow_lock); - - if (G_UNLIKELY (xvimagesink->xwindow == NULL)) { - g_mutex_unlock (xvimagesink->flow_lock); - return FALSE; - } - - /* Draw borders when displaying the first frame. After this - draw borders only on expose event or after a size change. */ - if (!xvimagesink->cur_image || xvimagesink->draw_border) { - draw_border = TRUE; - xvimagesink->draw_border = FALSE; - } - - /* Store a reference to the last image we put, lose the previous one */ - if (xvimage && xvimagesink->cur_image != xvimage) { - if (xvimagesink->cur_image) { - GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image); - gst_buffer_unref (xvimagesink->cur_image); - } - GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage); - xvimagesink->cur_image = - GST_XVIMAGE_BUFFER (gst_buffer_ref (GST_BUFFER (xvimage))); - } - - /* Expose sends a NULL image, we take the latest frame */ - if (!xvimage) { - draw_border = TRUE; - if (xvimagesink->cur_image) { - xvimage = xvimagesink->cur_image; - } else { - g_mutex_unlock (xvimagesink->flow_lock); - return TRUE; - } - } - - gst_xvimagesink_xwindow_update_geometry (xvimagesink, xvimagesink->xwindow); - - /* We use the calculated geometry from _setcaps as a source to respect - source and screen pixel aspect ratios. */ - src.w = GST_VIDEO_SINK_WIDTH (xvimagesink); - src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink); - dst.w = xvimagesink->xwindow->width; - dst.h = xvimagesink->xwindow->height; - - if (xvimagesink->keep_aspect) { - gst_video_sink_center_rect (src, dst, &result, TRUE); - } else { - result.x = result.y = 0; - result.w = dst.w; - result.h = dst.h; - } - - g_mutex_lock (xvimagesink->x_lock); - - if (draw_border) { - gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow, - result); - } - - /* We scale to the window's geometry */ -#ifdef HAVE_XSHM - if (xvimagesink->xcontext->use_xshm) { - GST_LOG_OBJECT (xvimagesink, - "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %" - GST_PTR_FORMAT, - xvimage->width, xvimage->height, - xvimagesink->xwindow->width, xvimagesink->xwindow->height, xvimage); - - XvShmPutImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimagesink->xwindow->win, - xvimagesink->xwindow->gc, xvimage->xvimage, - 0, 0, xvimage->width, xvimage->height, - result.x, result.y, result.w, result.h, FALSE); - } else -#endif /* HAVE_XSHM */ - { - XvPutImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimagesink->xwindow->win, - xvimagesink->xwindow->gc, xvimage->xvimage, - 0, 0, xvimage->width, xvimage->height, - result.x, result.y, result.w, result.h); - } - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); - - g_mutex_unlock (xvimagesink->flow_lock); - - return TRUE; -} - -static gboolean -gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink, - GstXWindow * window) -{ - Atom hints_atom = None; - MotifWmHints *hints; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE); - g_return_val_if_fail (window != NULL, FALSE); - - g_mutex_lock (xvimagesink->x_lock); - - hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS", - True); - if (hints_atom == None) { - g_mutex_unlock (xvimagesink->x_lock); - return FALSE; - } - - hints = g_malloc0 (sizeof (MotifWmHints)); - - hints->flags |= MWM_HINTS_DECORATIONS; - hints->decorations = 1 << 0; - - XChangeProperty (xvimagesink->xcontext->disp, window->win, - hints_atom, hints_atom, 32, PropModeReplace, - (guchar *) hints, sizeof (MotifWmHints) / sizeof (long)); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); - - g_free (hints); - - return TRUE; -} - -/* This function handles a GstXWindow creation - * The width and height are the actual pixel size on the display */ -static GstXWindow * -gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink, - gint width, gint height) -{ - GstXWindow *xwindow = NULL; - XGCValues values; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - xwindow = g_new0 (GstXWindow, 1); - - xwindow->width = width; - xwindow->height = height; - xwindow->internal = TRUE; - - g_mutex_lock (xvimagesink->x_lock); - - xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp, - xvimagesink->xcontext->root, - 0, 0, xwindow->width, xwindow->height, - 0, 0, xvimagesink->xcontext->black); - - /* We have to do that to prevent X from redrawing the background on - * ConfigureNotify. This takes away flickering of video when resizing. */ - XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None); - - if (xvimagesink->handle_events) { - Atom wm_delete; - - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - - /* Tell the window manager we'd like delete client messages instead of - * being killed */ - wm_delete = XInternAtom (xvimagesink->xcontext->disp, - "WM_DELETE_WINDOW", True); - if (wm_delete != None) { - (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win, - &wm_delete, 1); - } - } - - xwindow->gc = XCreateGC (xvimagesink->xcontext->disp, - xwindow->win, 0, &values); - - XMapRaised (xvimagesink->xcontext->disp, xwindow->win); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); - - gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow); - - gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (xvimagesink), xwindow->win); - - return xwindow; -} - -/* This function destroys a GstXWindow */ -static void -gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink, - GstXWindow * xwindow) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - g_mutex_lock (xvimagesink->x_lock); - - /* If we did not create that window we just free the GC and let it live */ - if (xwindow->internal) - XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win); - else - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0); - - XFreeGC (xvimagesink->xcontext->disp, xwindow->gc); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); - - g_free (xwindow); -} - -static void -gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink, - GstXWindow * xwindow) -{ - XWindowAttributes attr; - - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - /* Update the window geometry */ - g_mutex_lock (xvimagesink->x_lock); - - XGetWindowAttributes (xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, &attr); - - xvimagesink->xwindow->width = attr.width; - xvimagesink->xwindow->height = attr.height; - - g_mutex_unlock (xvimagesink->x_lock); -} - -static void -gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink, - GstXWindow * xwindow) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - g_mutex_lock (xvimagesink->x_lock); - - XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, - xwindow->win); - - XSetForeground (xvimagesink->xcontext->disp, xwindow->gc, - xvimagesink->xcontext->black); - - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, xwindow->width, xwindow->height); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); -} - -/* This function commits our internal colorbalance settings to our grabbed Xv - port. If the xcontext is not initialized yet it simply returns */ -static void -gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink) -{ - GList *channels = NULL; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - /* If we haven't initialized the X context we can't update anything */ - if (xvimagesink->xcontext == NULL) - return; - - /* For each channel of the colorbalance we calculate the correct value - doing range conversion and then set the Xv port attribute to match our - values. */ - channels = xvimagesink->xcontext->channels_list; - - while (channels) { - if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) { - GstColorBalanceChannel *channel = NULL; - Atom prop_atom; - gint value = 0; - gdouble convert_coef; - - channel = GST_COLOR_BALANCE_CHANNEL (channels->data); - g_object_ref (channel); - - /* Our range conversion coef */ - convert_coef = (channel->max_value - channel->min_value) / 2000.0; - - if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { - value = (xvimagesink->hue + 1000) * convert_coef + channel->min_value; - } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { - value = (xvimagesink->saturation + 1000) * convert_coef + - channel->min_value; - } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { - value = (xvimagesink->contrast + 1000) * convert_coef + - channel->min_value; - } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { - value = (xvimagesink->brightness + 1000) * convert_coef + - channel->min_value; - } else { - g_warning ("got an unknown channel %s", channel->label); - g_object_unref (channel); - return; - } - - /* Committing to Xv port */ - g_mutex_lock (xvimagesink->x_lock); - prop_atom = - XInternAtom (xvimagesink->xcontext->disp, channel->label, True); - if (prop_atom != None) { - XvSetPortAttribute (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, prop_atom, value); - } - g_mutex_unlock (xvimagesink->x_lock); - - g_object_unref (channel); - } - channels = g_list_next (channels); - } -} - -/* This function handles XEvents that might be in the queue. It generates - GstEvent that will be sent upstream in the pipeline to handle interactivity - and navigation. It will also listen for configure events on the window to - trigger caps renegotiation so on the fly software scaling can work. */ -static void -gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) -{ - XEvent e; - guint pointer_x = 0, pointer_y = 0; - gboolean pointer_moved = FALSE; - gboolean exposed = FALSE, configured = FALSE; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - /* We get all pointer motion events, only the last position is - interesting. */ - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - while (XCheckWindowEvent (xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, PointerMotionMask, &e)) { - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); - - switch (e.type) { - case MotionNotify: - pointer_x = e.xmotion.x; - pointer_y = e.xmotion.y; - pointer_moved = TRUE; - break; - default: - break; - } - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - } - if (pointer_moved) { - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); - - GST_DEBUG ("xvimagesink pointer moved over window at %d,%d", - pointer_x, pointer_y); - gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink), - "mouse-move", 0, e.xbutton.x, e.xbutton.y); - - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - } - - /* We get all events on our window to throw them upstream */ - while (XCheckWindowEvent (xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, - KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask, - &e)) { - KeySym keysym; - - /* We lock only for the X function call */ - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); - - switch (e.type) { - case ButtonPress: - /* Mouse button pressed over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d", - e.xbutton.button, e.xbutton.x, e.xbutton.y); - gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink), - "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y); - break; - case ButtonRelease: - /* Mouse button released over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("xvimagesink button %d released over window at %d,%d", - e.xbutton.button, e.xbutton.x, e.xbutton.y); - gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink), - "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y); - break; - case KeyPress: - case KeyRelease: - /* Key pressed/released over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("xvimagesink key %d pressed over window at %d,%d", - e.xkey.keycode, e.xkey.x, e.xkey.y); - g_mutex_lock (xvimagesink->x_lock); - keysym = XKeycodeToKeysym (xvimagesink->xcontext->disp, - e.xkey.keycode, 0); - g_mutex_unlock (xvimagesink->x_lock); - if (keysym != NoSymbol) { - char *key_str = NULL; - - g_mutex_lock (xvimagesink->x_lock); - key_str = XKeysymToString (keysym); - g_mutex_unlock (xvimagesink->x_lock); - gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink), - e.type == KeyPress ? "key-press" : "key-release", key_str); - } else { - gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink), - e.type == KeyPress ? "key-press" : "key-release", "unknown"); - } - break; - default: - GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type); - } - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - } - - /* Handle Expose */ - while (XCheckWindowEvent (xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) { - switch (e.type) { - case Expose: - exposed = TRUE; - break; - case ConfigureNotify: - configured = TRUE; - break; - default: - break; - } - } - - if (xvimagesink->handle_expose && (exposed || configured)) { - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); - - gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink)); - - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - } - - /* Handle Display events */ - while (XPending (xvimagesink->xcontext->disp)) { - XNextEvent (xvimagesink->xcontext->disp, &e); - - switch (e.type) { - case ClientMessage:{ - Atom wm_delete; - - wm_delete = XInternAtom (xvimagesink->xcontext->disp, - "WM_DELETE_WINDOW", True); - if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) { - /* Handle window deletion by posting an error on the bus */ - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND, - ("Output window was closed"), (NULL)); - - g_mutex_unlock (xvimagesink->x_lock); - gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); - xvimagesink->xwindow = NULL; - g_mutex_lock (xvimagesink->x_lock); - } - break; - } - default: - break; - } - } - - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); -} - -static void -gst_lookup_xv_port_from_adaptor (GstXContext * xcontext, - XvAdaptorInfo * adaptors, int adaptor_no) -{ - gint j; - - /* Do we support XvImageMask ? */ - if (!(adaptors[adaptor_no].type & XvImageMask)) - return; - - /* We found such an adaptor, looking for an available port */ - for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) { - /* We try to grab the port */ - if (Success == XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, - 0)) { - xcontext->xv_port_id = adaptors[adaptor_no].base_id + j; - GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name, - adaptors[adaptor_no].num_ports); - } - } -} - -/* This function generates a caps with all supported format by the first - Xv grabable port we find. We store each one of the supported formats in a - format list and append the format to a newly created caps that we return - If this function does not return NULL because of an error, it also grabs - the port via XvGrabPort */ -static GstCaps * -gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink, - GstXContext * xcontext) -{ - gint i; - XvAdaptorInfo *adaptors; - gint nb_formats; - XvImageFormatValues *formats = NULL; - guint nb_encodings; - XvEncodingInfo *encodings = NULL; - gulong max_w = G_MAXINT, max_h = G_MAXINT; - GstCaps *caps = NULL; - GstCaps *rgb_caps = NULL; - - g_return_val_if_fail (xcontext != NULL, NULL); - - /* First let's check that XVideo extension is available */ - if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) { - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, - ("Could not initialise Xv output"), - ("XVideo extension is not available")); - return NULL; - } - - /* Then we get adaptors list */ - if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root, - &xcontext->nb_adaptors, &adaptors)) { - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, - ("Could not initialise Xv output"), - ("Failed getting XV adaptors list")); - return NULL; - } - - xcontext->xv_port_id = 0; - - GST_DEBUG ("Found %u XV adaptor(s)", xcontext->nb_adaptors); - - xcontext->adaptors = - (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *)); - - /* Now fill up our adaptor name array */ - for (i = 0; i < xcontext->nb_adaptors; i++) { - xcontext->adaptors[i] = g_strdup (adaptors[i].name); - } - - if (xvimagesink->adaptor_no >= 0 && - xvimagesink->adaptor_no < xcontext->nb_adaptors) { - /* Find xv port from user defined adaptor */ - gst_lookup_xv_port_from_adaptor (xcontext, adaptors, - xvimagesink->adaptor_no); - } - - if (!xcontext->xv_port_id) { - /* Now search for an adaptor that supports XvImageMask */ - for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) { - gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i); - xvimagesink->adaptor_no = i; - } - } - - XvFreeAdaptorInfo (adaptors); - - if (!xcontext->xv_port_id) { - xvimagesink->adaptor_no = -1; - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY, - ("Could not initialise Xv output"), ("No port available")); - return NULL; - } - - /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */ - { - int count; - XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp, - xcontext->xv_port_id, &count); - static const char autopaint[] = "XV_AUTOPAINT_COLORKEY"; - static const char dbl_buffer[] = "XV_DOUBLE_BUFFER"; - static const char colorkey[] = "XV_COLORKEY"; - - for (i = 0; i < count; i++) - if (!strcmp (attr[i].name, autopaint)) { - const Atom atom = XInternAtom (xcontext->disp, autopaint, False); - - XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, 1); - break; - } - - for (i = 0; i < count; i++) - if (!strcmp (attr[i].name, dbl_buffer)) { - const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False); - - XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, - (xvimagesink->double_buffer ? 1 : 0)); - break; - } - - /* Set the colorkey to something that is dark but hopefully won't randomly - * appear on the screen elsewhere (ie not black or greys) */ - for (i = 0; i < count; i++) - if (!strcmp (attr[i].name, colorkey)) { - const Atom atom = XInternAtom (xcontext->disp, colorkey, False); - guint32 ckey; - guint32 keymask; - gint bits; - gboolean set_attr = TRUE; - - /* Count the bits in the colorkey mask 'max' value */ - bits = 0; - for (keymask = (guint32) (attr[i].max_value); - keymask != 0; keymask >>= 1) - bits++; - - /* set a colorkey in the right format RGB565/RGB888 - * note that the colorkey is independent from the display - * depth (xcontext->depth). We only handle these 2 cases, because - * they're the only types of devices we've encountered. If we don't - * recognise it, leave it alone */ - if (bits == 16) - ckey = (1 << 10) | (2 << 5) | 3; - else if (bits == 24 || bits == 32) - ckey = (1 << 16) | (2 << 8) | 3; - else - set_attr = FALSE; - - - if (set_attr) { - ckey = CLAMP (ckey, (guint32) attr[i].min_value, - (guint32) attr[i].max_value); - GST_LOG_OBJECT (xvimagesink, - "Setting color key for display depth %d to 0x%x", - xcontext->depth, ckey); - - XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, - (gint) ckey); - } else { - GST_LOG_OBJECT (xvimagesink, - "Unknown bit depth for Xv Colorkey - not adjusting "); - } - break; - } - - XFree (attr); - } - - /* Get the list of encodings supported by the adapter and look for the - * XV_IMAGE encoding so we can determine the maximum width and height - * supported */ - XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings, - &encodings); - - for (i = 0; i < nb_encodings; i++) { - GST_LOG_OBJECT (xvimagesink, - "Encoding %d, name %s, max wxh %lux%lu rate %d/%d", - i, encodings[i].name, encodings[i].width, encodings[i].height, - encodings[i].rate.numerator, encodings[i].rate.denominator); - if (strcmp (encodings[i].name, "XV_IMAGE") == 0) { - max_w = encodings[i].width; - max_h = encodings[i].height; - } - } - - XvFreeEncodingInfo (encodings); - - /* We get all image formats supported by our port */ - formats = XvListImageFormats (xcontext->disp, - xcontext->xv_port_id, &nb_formats); - caps = gst_caps_new_empty (); - for (i = 0; i < nb_formats; i++) { - GstCaps *format_caps = NULL; - gboolean is_rgb_format = FALSE; - - /* We set the image format of the xcontext to an existing one. This - is just some valid image format for making our xshm calls check before - caps negotiation really happens. */ - xcontext->im_format = formats[i].id; - - switch (formats[i].type) { - case XvRGB: - { - XvImageFormatValues *fmt = &(formats[i]); - gint endianness = G_BIG_ENDIAN; - - if (fmt->byte_order == LSBFirst) { - /* our caps system handles 24/32bpp RGB as big-endian. */ - if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) { - fmt->red_mask = GUINT32_TO_BE (fmt->red_mask); - fmt->green_mask = GUINT32_TO_BE (fmt->green_mask); - fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask); - - if (fmt->bits_per_pixel == 24) { - fmt->red_mask >>= 8; - fmt->green_mask >>= 8; - fmt->blue_mask >>= 8; - } - } else - endianness = G_LITTLE_ENDIAN; - } - - format_caps = gst_caps_new_simple ("video/x-raw-rgb", - "endianness", G_TYPE_INT, endianness, - "depth", G_TYPE_INT, fmt->depth, - "bpp", G_TYPE_INT, fmt->bits_per_pixel, - "red_mask", G_TYPE_INT, fmt->red_mask, - "green_mask", G_TYPE_INT, fmt->green_mask, - "blue_mask", G_TYPE_INT, fmt->blue_mask, - "width", GST_TYPE_INT_RANGE, 1, max_w, - "height", GST_TYPE_INT_RANGE, 1, max_h, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - - is_rgb_format = TRUE; - break; - } - case XvYUV: - format_caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, formats[i].id, - "width", GST_TYPE_INT_RANGE, 1, max_w, - "height", GST_TYPE_INT_RANGE, 1, max_h, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - break; - default: - g_assert_not_reached (); - break; - } - - if (format_caps) { - GstXvImageFormat *format = NULL; - - format = g_new0 (GstXvImageFormat, 1); - if (format) { - format->format = formats[i].id; - format->caps = gst_caps_copy (format_caps); - xcontext->formats_list = g_list_append (xcontext->formats_list, format); - } - - if (is_rgb_format) { - if (rgb_caps == NULL) - rgb_caps = format_caps; - else - gst_caps_append (rgb_caps, format_caps); - } else - gst_caps_append (caps, format_caps); - } - } - - /* Collected all caps into either the caps or rgb_caps structures. - * Append rgb_caps on the end of YUV, so that YUV is always preferred */ - if (rgb_caps) - gst_caps_append (caps, rgb_caps); - - if (formats) - XFree (formats); - - GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps); - - if (gst_caps_is_empty (caps)) { - gst_caps_unref (caps); - XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0); - GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL), - ("No supported format found")); - return NULL; - } - - return caps; -} - -static gpointer -gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink) -{ - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - GST_OBJECT_LOCK (xvimagesink); - while (xvimagesink->running) { - GST_OBJECT_UNLOCK (xvimagesink); - - if (xvimagesink->xwindow) { - gst_xvimagesink_handle_xevents (xvimagesink); - } - g_usleep (50000); - - GST_OBJECT_LOCK (xvimagesink); - } - GST_OBJECT_UNLOCK (xvimagesink); - - return NULL; -} - -/* This function calculates the pixel aspect ratio based on the properties - * in the xcontext structure and stores it there. */ -static void -gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext) -{ - static const gint par[][2] = { - {1, 1}, /* regular screen */ - {16, 15}, /* PAL TV */ - {11, 10}, /* 525 line Rec.601 video */ - {54, 59}, /* 625 line Rec.601 video */ - {64, 45}, /* 1280x1024 on 16:9 display */ - {5, 3}, /* 1280x1024 on 4:3 display */ - {4, 3} /* 800x600 on 16:9 display */ - }; - gint i; - gint index; - gdouble ratio; - gdouble delta; - -#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1]))) - - /* first calculate the "real" ratio based on the X values; - * which is the "physical" w/h divided by the w/h in pixels of the display */ - ratio = (gdouble) (xcontext->widthmm * xcontext->height) - / (xcontext->heightmm * xcontext->width); - - /* DirectFB's X in 720x576 reports the physical dimensions wrong, so - * override here */ - if (xcontext->width == 720 && xcontext->height == 576) { - ratio = 4.0 * 576 / (3.0 * 720); - } - GST_DEBUG ("calculated pixel aspect ratio: %f", ratio); - /* now find the one from par[][2] with the lowest delta to the real one */ - delta = DELTA (0); - index = 0; - - for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) { - gdouble this_delta = DELTA (i); - - if (this_delta < delta) { - index = i; - delta = this_delta; - } - } - - GST_DEBUG ("Decided on index %d (%d/%d)", index, - par[index][0], par[index][1]); - - g_free (xcontext->par); - xcontext->par = g_new0 (GValue, 1); - g_value_init (xcontext->par, GST_TYPE_FRACTION); - gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]); - GST_DEBUG ("set xcontext PAR to %d/%d", - gst_value_get_fraction_numerator (xcontext->par), - gst_value_get_fraction_denominator (xcontext->par)); -} - -/* This function gets the X Display and global info about it. Everything is - stored in our object and will be cleaned when the object is disposed. Note - here that caps for supported format are generated without any window or - image creation */ -static GstXContext * -gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) -{ - GstXContext *xcontext = NULL; - XPixmapFormatValues *px_formats = NULL; - gint nb_formats = 0, i, j, N_attr; - XvAttribute *xv_attr; - Atom prop_atom; - char *channels[4] = { "XV_HUE", "XV_SATURATION", - "XV_BRIGHTNESS", "XV_CONTRAST" - }; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - xcontext = g_new0 (GstXContext, 1); - xcontext->im_format = 0; - - g_mutex_lock (xvimagesink->x_lock); - - xcontext->disp = XOpenDisplay (xvimagesink->display_name); - - if (!xcontext->disp) { - g_mutex_unlock (xvimagesink->x_lock); - g_free (xcontext); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Could not initialise Xv output"), ("Could not open display")); - return NULL; - } - - xcontext->screen = DefaultScreenOfDisplay (xcontext->disp); - xcontext->screen_num = DefaultScreen (xcontext->disp); - xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num); - xcontext->root = DefaultRootWindow (xcontext->disp); - xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num); - xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num); - xcontext->depth = DefaultDepthOfScreen (xcontext->screen); - - xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num); - xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num); - xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num); - xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num); - - GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm", - xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm); - - gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext); - /* We get supported pixmap formats at supported depth */ - px_formats = XListPixmapFormats (xcontext->disp, &nb_formats); - - if (!px_formats) { - XCloseDisplay (xcontext->disp); - g_mutex_unlock (xvimagesink->x_lock); - g_free (xcontext->par); - g_free (xcontext); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, - ("Could not initialise Xv output"), ("Could not get pixel formats")); - return NULL; - } - - /* We get bpp value corresponding to our running depth */ - for (i = 0; i < nb_formats; i++) { - if (px_formats[i].depth == xcontext->depth) - xcontext->bpp = px_formats[i].bits_per_pixel; - } - - XFree (px_formats); - - xcontext->endianness = - (ImageByteOrder (xcontext->disp) == - LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN; - - /* our caps system handles 24/32bpp RGB as big-endian. */ - if ((xcontext->bpp == 24 || xcontext->bpp == 32) && - xcontext->endianness == G_LITTLE_ENDIAN) { - xcontext->endianness = G_BIG_ENDIAN; - xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask); - xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask); - xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask); - if (xcontext->bpp == 24) { - xcontext->visual->red_mask >>= 8; - xcontext->visual->green_mask >>= 8; - xcontext->visual->blue_mask >>= 8; - } - } - - xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext); - - if (!xcontext->caps) { - XCloseDisplay (xcontext->disp); - g_mutex_unlock (xvimagesink->x_lock); - g_free (xcontext->par); - g_free (xcontext); - /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */ - return NULL; - } -#ifdef HAVE_XSHM - /* Search for XShm extension support */ - if (XShmQueryExtension (xcontext->disp) && - gst_xvimagesink_check_xshm_calls (xcontext)) { - xcontext->use_xshm = TRUE; - GST_DEBUG ("xvimagesink is using XShm extension"); - } else -#endif /* HAVE_XSHM */ - { - xcontext->use_xshm = FALSE; - GST_DEBUG ("xvimagesink is not using XShm extension"); - } - - xv_attr = XvQueryPortAttributes (xcontext->disp, - xcontext->xv_port_id, &N_attr); - - - /* Generate the channels list */ - for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) { - XvAttribute *matching_attr = NULL; - - /* Retrieve the property atom if it exists. If it doesn't exist, - * the attribute itself must not either, so we can skip */ - prop_atom = XInternAtom (xcontext->disp, channels[i], True); - if (prop_atom == None) - continue; - - if (xv_attr != NULL) { - for (j = 0; j < N_attr && matching_attr == NULL; ++j) - if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name)) - matching_attr = xv_attr + j; - } - - if (matching_attr) { - GstColorBalanceChannel *channel; - - channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL); - channel->label = g_strdup (channels[i]); - channel->min_value = matching_attr ? matching_attr->min_value : -1000; - channel->max_value = matching_attr ? matching_attr->max_value : 1000; - - xcontext->channels_list = g_list_append (xcontext->channels_list, - channel); - - /* If the colorbalance settings have not been touched we get Xv values - as defaults and update our internal variables */ - if (!xvimagesink->cb_changed) { - gint val; - - XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id, - prop_atom, &val); - /* Normalize val to [-1000, 1000] */ - val = -1000 + 2000 * (val - channel->min_value) / - (channel->max_value - channel->min_value); - - if (!g_ascii_strcasecmp (channels[i], "XV_HUE")) - xvimagesink->hue = val; - else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION")) - xvimagesink->saturation = val; - else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS")) - xvimagesink->brightness = val; - else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST")) - xvimagesink->contrast = val; - } - } - } - - if (xv_attr) - XFree (xv_attr); - - g_mutex_unlock (xvimagesink->x_lock); - - /* Setup our event listening thread */ - GST_OBJECT_LOCK (xvimagesink); - xvimagesink->running = TRUE; - xvimagesink->event_thread = g_thread_create ( - (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL); - GST_OBJECT_UNLOCK (xvimagesink); - - return xcontext; -} - -/* This function cleans the X context. Closing the Display, releasing the XV - port and unrefing the caps for supported formats. */ -static void -gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink) -{ - GList *formats_list, *channels_list; - GstXContext *xcontext; - gint i = 0; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - GST_OBJECT_LOCK (xvimagesink); - if (xvimagesink->xcontext == NULL) { - GST_OBJECT_UNLOCK (xvimagesink); - return; - } - - /* Take the XContext from the sink and clean it up */ - xcontext = xvimagesink->xcontext; - xvimagesink->xcontext = NULL; - - GST_OBJECT_UNLOCK (xvimagesink); - - - formats_list = xcontext->formats_list; - - while (formats_list) { - GstXvImageFormat *format = formats_list->data; - - gst_caps_unref (format->caps); - g_free (format); - formats_list = g_list_next (formats_list); - } - - if (xcontext->formats_list) - g_list_free (xcontext->formats_list); - - channels_list = xcontext->channels_list; - - while (channels_list) { - GstColorBalanceChannel *channel = channels_list->data; - - g_object_unref (channel); - channels_list = g_list_next (channels_list); - } - - if (xcontext->channels_list) - g_list_free (xcontext->channels_list); - - gst_caps_unref (xcontext->caps); - if (xcontext->last_caps) - gst_caps_replace (&xcontext->last_caps, NULL); - - for (i = 0; i < xcontext->nb_adaptors; i++) { - g_free (xcontext->adaptors[i]); - } - - g_free (xcontext->adaptors); - - g_free (xcontext->par); - - g_mutex_lock (xvimagesink->x_lock); - - GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context"); - - XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0); - - XCloseDisplay (xcontext->disp); - - g_mutex_unlock (xvimagesink->x_lock); - - g_free (xcontext); -} - -static void -gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink) -{ - g_mutex_lock (xvimagesink->pool_lock); - - while (xvimagesink->image_pool) { - GstXvImageBuffer *xvimage = xvimagesink->image_pool->data; - - xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool, - xvimagesink->image_pool); - gst_xvimage_buffer_free (xvimage); - } - - g_mutex_unlock (xvimagesink->pool_lock); -} - -/* Element stuff */ - -/* This function tries to get a format matching with a given caps in the - supported list of formats we generated in gst_xvimagesink_get_xv_support */ -static gint -gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink, - GstCaps * caps) -{ - GList *list = NULL; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0); - - list = xvimagesink->xcontext->formats_list; - - while (list) { - GstXvImageFormat *format = list->data; - - if (format) { - GstCaps *icaps = NULL; - - icaps = gst_caps_intersect (caps, format->caps); - if (!gst_caps_is_empty (icaps)) { - gst_caps_unref (icaps); - return format->format; - } - gst_caps_unref (icaps); - } - list = g_list_next (list); - } - - return -1; -} - -static GstCaps * -gst_xvimagesink_getcaps (GstBaseSink * bsink) -{ - GstXvImageSink *xvimagesink; - - xvimagesink = GST_XVIMAGESINK (bsink); - - if (xvimagesink->xcontext) - return gst_caps_ref (xvimagesink->xcontext->caps); - - return - gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD - (xvimagesink))); -} - -static gboolean -gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) -{ - GstXvImageSink *xvimagesink; - GstStructure *structure; - GstCaps *intersection; - guint32 im_format = 0; - gboolean ret; - gint video_width, video_height; - gint video_par_n, video_par_d; /* video's PAR */ - gint display_par_n, display_par_d; /* display's PAR */ - const GValue *caps_par; - const GValue *fps; - guint num, den; - - xvimagesink = GST_XVIMAGESINK (bsink); - - GST_DEBUG_OBJECT (xvimagesink, - "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %" - GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps); - - intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps); - GST_DEBUG_OBJECT (xvimagesink, "intersection returned %" GST_PTR_FORMAT, - intersection); - if (gst_caps_is_empty (intersection)) { - gst_caps_unref (intersection); - return FALSE; - } - - gst_caps_unref (intersection); - - structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "width", &video_width); - ret &= gst_structure_get_int (structure, "height", &video_height); - fps = gst_structure_get_value (structure, "framerate"); - ret &= (fps != NULL); - - if (!ret) { - GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, " - "height or framerate from intersected caps"); - return FALSE; - } - - xvimagesink->fps_n = gst_value_get_fraction_numerator (fps); - xvimagesink->fps_d = gst_value_get_fraction_denominator (fps); - - xvimagesink->video_width = video_width; - xvimagesink->video_height = video_height; - im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps); - if (im_format == -1) { - GST_DEBUG_OBJECT (xvimagesink, - "Could not locate image format from caps %" GST_PTR_FORMAT, caps); - return FALSE; - } - - /* get aspect ratio from caps if it's present, and - * convert video width and height to a display width and height - * using wd / hd = wv / hv * PARv / PARd */ - - /* get video's PAR */ - caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - if (caps_par) { - video_par_n = gst_value_get_fraction_numerator (caps_par); - video_par_d = gst_value_get_fraction_denominator (caps_par); - } else { - video_par_n = 1; - video_par_d = 1; - } - /* get display's PAR */ - if (xvimagesink->par) { - display_par_n = gst_value_get_fraction_numerator (xvimagesink->par); - display_par_d = gst_value_get_fraction_denominator (xvimagesink->par); - } else { - display_par_n = 1; - display_par_d = 1; - } - - if (!gst_video_calculate_display_ratio (&num, &den, video_width, - video_height, video_par_n, video_par_d, display_par_n, - display_par_d)) { - GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL), - ("Error calculating the output display ratio of the video.")); - return FALSE; - } - - GST_DEBUG_OBJECT (xvimagesink, - "video width/height: %dx%d, calculated display ratio: %d/%d", - video_width, video_height, num, den); - - /* now find a width x height that respects this display ratio. - * prefer those that have one of w/h the same as the incoming video - * using wd / hd = num / den */ - - /* start with same height, because of interlaced video */ - /* check hd / den is an integer scale factor, and scale wd with the PAR */ - if (video_height % den == 0) { - GST_DEBUG_OBJECT (xvimagesink, "keeping video height"); - GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint) - gst_util_uint64_scale_int (video_height, num, den); - GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height; - } else if (video_width % num == 0) { - GST_DEBUG_OBJECT (xvimagesink, "keeping video width"); - GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width; - GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint) - gst_util_uint64_scale_int (video_width, den, num); - } else { - GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height"); - GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint) - gst_util_uint64_scale_int (video_height, num, den); - GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height; - } - GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d", - GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink)); - - /* Notify application to set xwindow id now */ - g_mutex_lock (xvimagesink->flow_lock); - if (!xvimagesink->xwindow) { - g_mutex_unlock (xvimagesink->flow_lock); - gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink)); - } else { - g_mutex_unlock (xvimagesink->flow_lock); - } - - /* Creating our window and our image with the display size in pixels */ - if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 || - GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0) { - GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL), - ("Error calculating the output display ratio of the video.")); - return FALSE; - } - - g_mutex_lock (xvimagesink->flow_lock); - if (!xvimagesink->xwindow) { - xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink, - GST_VIDEO_SINK_WIDTH (xvimagesink), - GST_VIDEO_SINK_HEIGHT (xvimagesink)); - } - - /* After a resize, we want to redraw the borders in case the new frame size - * doesn't cover the same area */ - xvimagesink->draw_border = TRUE; - - /* We renew our xvimage only if size or format changed; - * the xvimage is the same size as the video pixel size */ - if ((xvimagesink->xvimage) && - ((im_format != xvimagesink->xvimage->im_format) || - (video_width != xvimagesink->xvimage->width) || - (video_height != xvimagesink->xvimage->height))) { - GST_DEBUG_OBJECT (xvimagesink, - "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (xvimagesink->xvimage->im_format), - GST_FOURCC_ARGS (im_format)); - GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage"); - gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage)); - xvimagesink->xvimage = NULL; - } - - g_mutex_unlock (xvimagesink->flow_lock); - - return TRUE; -} - -static GstStateChangeReturn -gst_xvimagesink_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstXvImageSink *xvimagesink; - GstXContext *xcontext = NULL; - - xvimagesink = GST_XVIMAGESINK (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - /* Initializing the XContext */ - if (xvimagesink->xcontext == NULL) { - xcontext = gst_xvimagesink_xcontext_get (xvimagesink); - if (xcontext == NULL) - return GST_STATE_CHANGE_FAILURE; - GST_OBJECT_LOCK (xvimagesink); - if (xcontext) - xvimagesink->xcontext = xcontext; - GST_OBJECT_UNLOCK (xvimagesink); - } - - /* update object's par with calculated one if not set yet */ - if (!xvimagesink->par) { - xvimagesink->par = g_new0 (GValue, 1); - gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par); - GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR"); - } - /* call XSynchronize with the current value of synchronous */ - GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s", - xvimagesink->synchronous ? "TRUE" : "FALSE"); - XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous); - gst_xvimagesink_update_colorbalance (xvimagesink); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - g_mutex_lock (xvimagesink->flow_lock); - if (xvimagesink->xwindow) - gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow); - g_mutex_unlock (xvimagesink->flow_lock); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - xvimagesink->fps_n = 0; - xvimagesink->fps_d = 1; - GST_VIDEO_SINK_WIDTH (xvimagesink) = 0; - GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0; - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_xvimagesink_reset (xvimagesink); - break; - default: - break; - } - - return ret; -} - -static void -gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf, - GstClockTime * start, GstClockTime * end) -{ - GstXvImageSink *xvimagesink; - - xvimagesink = GST_XVIMAGESINK (bsink); - - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - *start = GST_BUFFER_TIMESTAMP (buf); - if (GST_BUFFER_DURATION_IS_VALID (buf)) { - *end = *start + GST_BUFFER_DURATION (buf); - } else { - if (xvimagesink->fps_n > 0) { - *end = *start + - gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d, - xvimagesink->fps_n); - } - } - } -} - -static GstFlowReturn -gst_xvimagesink_show_frame (GstBaseSink * bsink, GstBuffer * buf) -{ - GstXvImageSink *xvimagesink; - - xvimagesink = GST_XVIMAGESINK (bsink); - - /* If this buffer has been allocated using our buffer management we simply - put the ximage which is in the PRIVATE pointer */ - if (GST_IS_XVIMAGE_BUFFER (buf)) { - GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer"); - if (!gst_xvimagesink_xvimage_put (xvimagesink, GST_XVIMAGE_BUFFER (buf))) - goto no_window; - } else { - GST_LOG_OBJECT (xvimagesink, "slow copy into bufferpool buffer"); - /* Else we have to copy the data into our private image, */ - /* if we have one... */ - if (!xvimagesink->xvimage) { - GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage"); - - xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink, - GST_BUFFER_CAPS (buf)); - - if (!xvimagesink->xvimage) - /* The create method should have posted an informative error */ - goto no_image; - - if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) { - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimagesink->xvimage->width, xvimagesink->xvimage->height), - ("XServer allocated buffer size did not match input buffer")); - - gst_xvimage_buffer_destroy (xvimagesink->xvimage); - xvimagesink->xvimage = NULL; - goto no_image; - } - } - - memcpy (xvimagesink->xvimage->xvimage->data, - GST_BUFFER_DATA (buf), - MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size)); - - if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage)) - goto no_window; - } - - return GST_FLOW_OK; - - /* ERRORS */ -no_image: - { - /* No image available. That's very bad ! */ - GST_WARNING_OBJECT (xvimagesink, "could not create image"); - return GST_FLOW_ERROR; - } -no_window: - { - /* No Window available to put our image into */ - GST_WARNING_OBJECT (xvimagesink, "could not output image - no window"); - return GST_FLOW_ERROR; - } -} - -/* Buffer management */ - -static GstFlowReturn -gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buf) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstXvImageSink *xvimagesink; - GstXvImageBuffer *xvimage = NULL; - GstCaps *intersection = NULL; - GstStructure *structure = NULL; - gint width, height, image_format; - - xvimagesink = GST_XVIMAGESINK (bsink); - - if (G_LIKELY (xvimagesink->xcontext->last_caps && - gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) { - GST_DEBUG_OBJECT (xvimagesink, - "buffer alloc for same last_caps, reusing caps"); - intersection = gst_caps_ref (caps); - image_format = xvimagesink->xcontext->last_format; - - goto reuse_last_caps; - } - - GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested with caps %" - GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, caps, - xvimagesink->xcontext->caps); - - /* Check the caps against our xcontext */ - intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps); - - /* Ensure the returned caps are fixed */ - gst_caps_truncate (intersection); - - GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %" - GST_PTR_FORMAT, intersection); - - if (gst_caps_is_empty (intersection)) { - /* So we don't support this kind of buffer, let's define one we'd like */ - GstCaps *new_caps = gst_caps_copy (caps); - - structure = gst_caps_get_structure (new_caps, 0); - - /* Try with YUV first */ - gst_structure_set_name (structure, "video/x-raw-yuv"); - gst_structure_remove_field (structure, "format"); - gst_structure_remove_field (structure, "endianness"); - gst_structure_remove_field (structure, "depth"); - gst_structure_remove_field (structure, "bpp"); - gst_structure_remove_field (structure, "red_mask"); - gst_structure_remove_field (structure, "green_mask"); - gst_structure_remove_field (structure, "blue_mask"); - gst_structure_remove_field (structure, "alpha_mask"); - - /* Reuse intersection with Xcontext */ - gst_caps_unref (intersection); - intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps); - - if (gst_caps_is_empty (intersection)) { - /* Now try with RGB */ - gst_structure_set_name (structure, "video/x-raw-rgb"); - /* And interset again */ - gst_caps_unref (intersection); - intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps); - - if (gst_caps_is_empty (intersection)) { - GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with " - "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT - " are completely incompatible with those caps", new_caps, - xvimagesink->xcontext->caps); - gst_caps_unref (new_caps); - ret = GST_FLOW_UNEXPECTED; - goto beach; - } - } - - /* Clean this copy */ - gst_caps_unref (new_caps); - /* We want fixed caps */ - gst_caps_truncate (intersection); - - GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %" - GST_PTR_FORMAT, intersection); - } else if (gst_caps_is_equal (intersection, caps)) { - /* Things work better if we return a buffer with the same caps ptr - * as was asked for when we can */ - gst_caps_replace (&intersection, caps); - } - - /* Get image format from caps */ - image_format = gst_xvimagesink_get_format_from_caps (xvimagesink, - intersection); - - /* Store our caps and format as the last_caps to avoid expensive - * caps intersection next time */ - gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection); - xvimagesink->xcontext->last_format = image_format; - -reuse_last_caps: - - /* Get geometry from caps */ - structure = gst_caps_get_structure (intersection, 0); - if (!gst_structure_get_int (structure, "width", &width) || - !gst_structure_get_int (structure, "height", &height) || - image_format == -1) { - GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %" - GST_PTR_FORMAT, intersection); - ret = GST_FLOW_UNEXPECTED; - goto beach; - } - - g_mutex_lock (xvimagesink->pool_lock); - - /* Walking through the pool cleaning unusable images and searching for a - suitable one */ - while (xvimagesink->image_pool) { - xvimage = xvimagesink->image_pool->data; - - if (xvimage) { - /* Removing from the pool */ - xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool, - xvimagesink->image_pool); - - /* We check for geometry or image format changes */ - if ((xvimage->width != width) || - (xvimage->height != height) || (xvimage->im_format != image_format)) { - /* This image is unusable. Destroying... */ - gst_xvimage_buffer_free (xvimage); - xvimage = NULL; - } else { - /* We found a suitable image */ - GST_LOG_OBJECT (xvimagesink, "found usable image in pool"); - break; - } - } - } - - g_mutex_unlock (xvimagesink->pool_lock); - - if (!xvimage) { - /* We found no suitable image in the pool. Creating... */ - GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage"); - xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection); - if (xvimage && xvimage->size < size) { - /* This image is unusable. Destroying... */ - gst_xvimage_buffer_free (xvimage); - xvimage = NULL; - } - } - - if (xvimage) { - gst_buffer_set_caps (GST_BUFFER (xvimage), intersection); - } - - *buf = GST_BUFFER (xvimage); - -beach: - if (intersection) { - gst_caps_unref (intersection); - } - - return ret; -} - -/* Interfaces stuff */ - -static gboolean -gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type) -{ - g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY || - type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE); - return TRUE; -} - -static void -gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass) -{ - klass->supported = gst_xvimagesink_interface_supported; -} - -static void -gst_xvimagesink_navigation_send_event (GstNavigation * navigation, - GstStructure * structure) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation); - GstPad *peer; - - if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) { - GstEvent *event; - GstVideoRectangle src, dst, result; - gdouble x, y, xscale = 1.0, yscale = 1.0; - - event = gst_event_new_navigation (structure); - - /* We take the flow_lock while we look at the window */ - g_mutex_lock (xvimagesink->flow_lock); - - if (!xvimagesink->xwindow) { - g_mutex_unlock (xvimagesink->flow_lock); - return; - } - - /* We get the frame position using the calculated geometry from _setcaps - that respect pixel aspect ratios */ - src.w = GST_VIDEO_SINK_WIDTH (xvimagesink); - src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink); - dst.w = xvimagesink->xwindow->width; - dst.h = xvimagesink->xwindow->height; - - g_mutex_unlock (xvimagesink->flow_lock); - - if (xvimagesink->keep_aspect) { - gst_video_sink_center_rect (src, dst, &result, TRUE); - } else { - result.x = result.y = 0; - result.w = dst.w; - result.h = dst.h; - } - - /* We calculate scaling using the original video frames geometry to include - pixel aspect ratio scaling. */ - xscale = (gdouble) xvimagesink->video_width / result.w; - yscale = (gdouble) xvimagesink->video_height / result.h; - - /* Converting pointer coordinates to the non scaled geometry */ - if (gst_structure_get_double (structure, "pointer_x", &x)) { - x = MIN (x, result.x + result.w); - x = MAX (x - result.x, 0); - gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, - (gdouble) x * xscale, NULL); - } - if (gst_structure_get_double (structure, "pointer_y", &y)) { - y = MIN (y, result.y + result.h); - y = MAX (y - result.y, 0); - gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, - (gdouble) y * yscale, NULL); - } - - gst_pad_send_event (peer, event); - gst_object_unref (peer); - } -} - -static void -gst_xvimagesink_navigation_init (GstNavigationInterface * iface) -{ - iface->send_event = gst_xvimagesink_navigation_send_event; -} - -static void -gst_xvimagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); - GstXWindow *xwindow = NULL; - XWindowAttributes attr; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - g_mutex_lock (xvimagesink->flow_lock); - - /* If we already use that window return */ - if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) { - g_mutex_unlock (xvimagesink->flow_lock); - return; - } - - /* If the element has not initialized the X11 context try to do so */ - if (!xvimagesink->xcontext && - !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) { - g_mutex_unlock (xvimagesink->flow_lock); - /* we have thrown a GST_ELEMENT_ERROR now */ - return; - } - - gst_xvimagesink_update_colorbalance (xvimagesink); - - /* Clear image pool as the images are unusable anyway */ - gst_xvimagesink_imagepool_clear (xvimagesink); - - /* Clear the xvimage */ - if (xvimagesink->xvimage) { - gst_xvimage_buffer_free (xvimagesink->xvimage); - xvimagesink->xvimage = NULL; - } - - /* If a window is there already we destroy it */ - if (xvimagesink->xwindow) { - gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); - xvimagesink->xwindow = NULL; - } - - /* If the xid is 0 we go back to an internal window */ - if (xwindow_id == 0) { - /* If no width/height caps nego did not happen window will be created - during caps nego then */ - if (GST_VIDEO_SINK_WIDTH (xvimagesink) - && GST_VIDEO_SINK_HEIGHT (xvimagesink)) { - xwindow = - gst_xvimagesink_xwindow_new (xvimagesink, - GST_VIDEO_SINK_WIDTH (xvimagesink), - GST_VIDEO_SINK_HEIGHT (xvimagesink)); - } - } else { - xwindow = g_new0 (GstXWindow, 1); - - xwindow->win = xwindow_id; - - /* We get window geometry, set the event we want to receive, - and create a GC */ - g_mutex_lock (xvimagesink->x_lock); - XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr); - xwindow->width = attr.width; - xwindow->height = attr.height; - xwindow->internal = FALSE; - if (xvimagesink->handle_events) { - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask); - } - - xwindow->gc = XCreateGC (xvimagesink->xcontext->disp, - xwindow->win, 0, NULL); - g_mutex_unlock (xvimagesink->x_lock); - } - - if (xwindow) - xvimagesink->xwindow = xwindow; - - g_mutex_unlock (xvimagesink->flow_lock); -} - -static void -gst_xvimagesink_expose (GstXOverlay * overlay) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); - - gst_xvimagesink_xvimage_put (xvimagesink, NULL); -} - -static void -gst_xvimagesink_set_event_handling (GstXOverlay * overlay, - gboolean handle_events) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); - - xvimagesink->handle_events = handle_events; - - g_mutex_lock (xvimagesink->flow_lock); - - if (G_UNLIKELY (!xvimagesink->xwindow)) { - g_mutex_unlock (xvimagesink->flow_lock); - return; - } - - g_mutex_lock (xvimagesink->x_lock); - - if (handle_events) { - if (xvimagesink->xwindow->internal) { - XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, - ExposureMask | StructureNotifyMask | PointerMotionMask | - KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - } else { - XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, - ExposureMask | StructureNotifyMask | PointerMotionMask | - KeyPressMask | KeyReleaseMask); - } - } else { - XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0); - } - - g_mutex_unlock (xvimagesink->x_lock); - - g_mutex_unlock (xvimagesink->flow_lock); -} - -static void -gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface) -{ - iface->set_xwindow_id = gst_xvimagesink_set_xwindow_id; - iface->expose = gst_xvimagesink_expose; - iface->handle_events = gst_xvimagesink_set_event_handling; -} - -static const GList * -gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance); - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - if (xvimagesink->xcontext) - return xvimagesink->xcontext->channels_list; - else - return NULL; -} - -static void -gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance, - GstColorBalanceChannel * channel, gint value) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance); - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - g_return_if_fail (channel->label != NULL); - - xvimagesink->cb_changed = TRUE; - - /* Normalize val to [-1000, 1000] */ - value = -1000 + 2000 * (value - channel->min_value) / - (channel->max_value - channel->min_value); - - if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { - xvimagesink->hue = value; - } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { - xvimagesink->saturation = value; - } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { - xvimagesink->contrast = value; - } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { - xvimagesink->brightness = value; - } else { - g_warning ("got an unknown channel %s", channel->label); - return; - } - - gst_xvimagesink_update_colorbalance (xvimagesink); -} - -static gint -gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance, - GstColorBalanceChannel * channel) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance); - gint value = 0; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0); - g_return_val_if_fail (channel->label != NULL, 0); - - if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { - value = xvimagesink->hue; - } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { - value = xvimagesink->saturation; - } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { - value = xvimagesink->contrast; - } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { - value = xvimagesink->brightness; - } else { - g_warning ("got an unknown channel %s", channel->label); - } - - /* Normalize val to [channel->min_value, channel->max_value] */ - value = channel->min_value + (channel->max_value - channel->min_value) * - (value + 1000) / 2000; - - return value; -} - -static void -gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface) -{ - GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE; - iface->list_channels = gst_xvimagesink_colorbalance_list_channels; - iface->set_value = gst_xvimagesink_colorbalance_set_value; - iface->get_value = gst_xvimagesink_colorbalance_get_value; -} - -static const GList * -gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe) -{ - GObjectClass *klass = G_OBJECT_GET_CLASS (probe); - static GList *list = NULL; - - if (!list) { - list = g_list_append (NULL, g_object_class_find_property (klass, "device")); - } - - return list; -} - -static void -gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe); - - switch (prop_id) { - case ARG_DEVICE: - GST_DEBUG_OBJECT (xvimagesink, "probing device list"); - if (!xvimagesink->xcontext) { - GST_DEBUG_OBJECT (xvimagesink, "generating xcontext"); - xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } -} - -static gboolean -gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe); - gboolean ret = FALSE; - - switch (prop_id) { - case ARG_DEVICE: - if (xvimagesink->xcontext != NULL) { - ret = FALSE; - } else { - ret = TRUE; - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return ret; -} - -static GValueArray * -gst_xvimagesink_probe_get_values (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe); - GValueArray *array = NULL; - - if (G_UNLIKELY (!xvimagesink->xcontext)) { - GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't " - "get values"); - goto beach; - } - - switch (prop_id) { - case ARG_DEVICE: - { - guint i; - GValue value = { 0 }; - - array = g_value_array_new (xvimagesink->xcontext->nb_adaptors); - g_value_init (&value, G_TYPE_STRING); - - for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) { - gchar *adaptor_id_s = g_strdup_printf ("%u", i); - - g_value_set_string (&value, adaptor_id_s); - g_value_array_append (array, &value); - g_free (adaptor_id_s); - } - g_value_unset (&value); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - -beach: - return array; -} - -static void -gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface * - iface) -{ - iface->get_properties = gst_xvimagesink_probe_get_properties; - iface->probe_property = gst_xvimagesink_probe_probe_property; - iface->needs_probe = gst_xvimagesink_probe_needs_probe; - iface->get_values = gst_xvimagesink_probe_get_values; -} - -/* =========================================== */ -/* */ -/* Init & Class init */ -/* */ -/* =========================================== */ - -static void -gst_xvimagesink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstXvImageSink *xvimagesink; - - g_return_if_fail (GST_IS_XVIMAGESINK (object)); - - xvimagesink = GST_XVIMAGESINK (object); - - switch (prop_id) { - case ARG_HUE: - xvimagesink->hue = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; - gst_xvimagesink_update_colorbalance (xvimagesink); - break; - case ARG_CONTRAST: - xvimagesink->contrast = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; - gst_xvimagesink_update_colorbalance (xvimagesink); - break; - case ARG_BRIGHTNESS: - xvimagesink->brightness = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; - gst_xvimagesink_update_colorbalance (xvimagesink); - break; - case ARG_SATURATION: - xvimagesink->saturation = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; - gst_xvimagesink_update_colorbalance (xvimagesink); - break; - case ARG_DISPLAY: - xvimagesink->display_name = g_strdup (g_value_get_string (value)); - break; - case ARG_SYNCHRONOUS: - xvimagesink->synchronous = g_value_get_boolean (value); - if (xvimagesink->xcontext) { - XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous); - GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s", - xvimagesink->synchronous ? "TRUE" : "FALSE"); - } - break; - case ARG_PIXEL_ASPECT_RATIO: - g_free (xvimagesink->par); - xvimagesink->par = g_new0 (GValue, 1); - g_value_init (xvimagesink->par, GST_TYPE_FRACTION); - if (!g_value_transform (value, xvimagesink->par)) { - g_warning ("Could not transform string to aspect ratio"); - gst_value_set_fraction (xvimagesink->par, 1, 1); - } - GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d", - gst_value_get_fraction_numerator (xvimagesink->par), - gst_value_get_fraction_denominator (xvimagesink->par)); - break; - case ARG_FORCE_ASPECT_RATIO: - xvimagesink->keep_aspect = g_value_get_boolean (value); - break; - case ARG_HANDLE_EVENTS: - gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink), - g_value_get_boolean (value)); - break; - case ARG_DEVICE: - xvimagesink->adaptor_no = atoi (g_value_get_string (value)); - break; - case ARG_HANDLE_EXPOSE: - xvimagesink->handle_expose = g_value_get_boolean (value); - break; - case ARG_DOUBLE_BUFFER: - xvimagesink->double_buffer = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_xvimagesink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstXvImageSink *xvimagesink; - - g_return_if_fail (GST_IS_XVIMAGESINK (object)); - - xvimagesink = GST_XVIMAGESINK (object); - - switch (prop_id) { - case ARG_HUE: - g_value_set_int (value, xvimagesink->hue); - break; - case ARG_CONTRAST: - g_value_set_int (value, xvimagesink->contrast); - break; - case ARG_BRIGHTNESS: - g_value_set_int (value, xvimagesink->brightness); - break; - case ARG_SATURATION: - g_value_set_int (value, xvimagesink->saturation); - break; - case ARG_DISPLAY: - g_value_set_string (value, xvimagesink->display_name); - break; - case ARG_SYNCHRONOUS: - g_value_set_boolean (value, xvimagesink->synchronous); - break; - case ARG_PIXEL_ASPECT_RATIO: - if (xvimagesink->par) - g_value_transform (xvimagesink->par, value); - break; - case ARG_FORCE_ASPECT_RATIO: - g_value_set_boolean (value, xvimagesink->keep_aspect); - break; - case ARG_HANDLE_EVENTS: - g_value_set_boolean (value, xvimagesink->handle_events); - break; - case ARG_DEVICE: - { - char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no); - - g_value_set_string (value, adaptor_no_s); - g_free (adaptor_no_s); - break; - } - case ARG_DEVICE_NAME: - if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) { - g_value_set_string (value, - xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]); - } else { - g_value_set_string (value, NULL); - } - break; - case ARG_HANDLE_EXPOSE: - g_value_set_boolean (value, xvimagesink->handle_expose); - break; - case ARG_DOUBLE_BUFFER: - g_value_set_boolean (value, xvimagesink->double_buffer); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_xvimagesink_reset (GstXvImageSink * xvimagesink) -{ - GThread *thread; - - GST_OBJECT_LOCK (xvimagesink); - xvimagesink->running = FALSE; - /* grab thread and mark it as NULL */ - thread = xvimagesink->event_thread; - xvimagesink->event_thread = NULL; - GST_OBJECT_UNLOCK (xvimagesink); - - /* Wait for our event thread to finish before we clean up our stuff. */ - if (thread) - g_thread_join (thread); - - if (xvimagesink->cur_image) { - gst_buffer_unref (xvimagesink->cur_image); - xvimagesink->cur_image = NULL; - } - if (xvimagesink->xvimage) { - gst_buffer_unref (xvimagesink->xvimage); - xvimagesink->xvimage = NULL; - } - - gst_xvimagesink_imagepool_clear (xvimagesink); - - if (xvimagesink->xwindow) { - gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow); - gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); - xvimagesink->xwindow = NULL; - } - - gst_xvimagesink_xcontext_clear (xvimagesink); -} - -/* Finalize is called only once, dispose can be called multiple times. - * We use mutexes and don't reset stuff to NULL here so let's register - * as a finalize. */ -static void -gst_xvimagesink_finalize (GObject * object) -{ - GstXvImageSink *xvimagesink; - - xvimagesink = GST_XVIMAGESINK (object); - - gst_xvimagesink_reset (xvimagesink); - - if (xvimagesink->display_name) { - g_free (xvimagesink->display_name); - xvimagesink->display_name = NULL; - } - - if (xvimagesink->par) { - g_free (xvimagesink->par); - xvimagesink->par = NULL; - } - if (xvimagesink->x_lock) { - g_mutex_free (xvimagesink->x_lock); - xvimagesink->x_lock = NULL; - } - if (xvimagesink->flow_lock) { - g_mutex_free (xvimagesink->flow_lock); - xvimagesink->flow_lock = NULL; - } - if (xvimagesink->pool_lock) { - g_mutex_free (xvimagesink->pool_lock); - xvimagesink->pool_lock = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_xvimagesink_init (GstXvImageSink * xvimagesink) -{ - xvimagesink->display_name = NULL; - xvimagesink->adaptor_no = 0; - xvimagesink->xcontext = NULL; - xvimagesink->xwindow = NULL; - xvimagesink->xvimage = NULL; - xvimagesink->cur_image = NULL; - - xvimagesink->hue = xvimagesink->saturation = 0; - xvimagesink->contrast = xvimagesink->brightness = 0; - xvimagesink->cb_changed = FALSE; - - xvimagesink->fps_n = 0; - xvimagesink->fps_d = 0; - xvimagesink->video_width = 0; - xvimagesink->video_height = 0; - - xvimagesink->x_lock = g_mutex_new (); - xvimagesink->flow_lock = g_mutex_new (); - - xvimagesink->image_pool = NULL; - xvimagesink->pool_lock = g_mutex_new (); - - xvimagesink->synchronous = FALSE; - xvimagesink->double_buffer = TRUE; - xvimagesink->running = FALSE; - xvimagesink->keep_aspect = FALSE; - xvimagesink->handle_events = TRUE; - xvimagesink->par = NULL; - xvimagesink->handle_expose = TRUE; -} - -static void -gst_xvimagesink_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_xvimagesink_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_xvimagesink_sink_template_factory)); -} - -static void -gst_xvimagesink_class_init (GstXvImageSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->set_property = gst_xvimagesink_set_property; - gobject_class->get_property = gst_xvimagesink_get_property; - - g_object_class_install_property (gobject_class, ARG_CONTRAST, - g_param_spec_int ("contrast", "Contrast", "The contrast of the video", - -1000, 1000, 0, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_BRIGHTNESS, - g_param_spec_int ("brightness", "Brightness", - "The brightness of the video", -1000, 1000, 0, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_HUE, - g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0, - G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_SATURATION, - g_param_spec_int ("saturation", "Saturation", - "The saturation of the video", -1000, 1000, 0, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_DISPLAY, - g_param_spec_string ("display", "Display", "X Display name", NULL, - G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_SYNCHRONOUS, - g_param_spec_boolean ("synchronous", "Synchronous", - "When enabled, runs " - "the X display in synchronous mode. (used only for debugging)", FALSE, - G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_PIXEL_ASPECT_RATIO, - g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio", - "The pixel aspect ratio of the device", "1/1", G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_FORCE_ASPECT_RATIO, - g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio", - "When enabled, scaling will respect original aspect ratio", FALSE, - G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_HANDLE_EVENTS, - g_param_spec_boolean ("handle-events", "Handle XEvents", - "When enabled, XEvents will be selected and handled", TRUE, - G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_DEVICE, - g_param_spec_string ("device", "Adaptor number", - "The number of the video adaptor", "0", G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_DEVICE_NAME, - g_param_spec_string ("device-name", "Adaptor name", - "The name of the video adaptor", NULL, G_PARAM_READABLE)); - g_object_class_install_property (gobject_class, ARG_HANDLE_EXPOSE, - g_param_spec_boolean ("handle-expose", "Handle expose", "When enabled, " - "the current frame will always be drawn in response to X Expose " - "events", TRUE, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_DOUBLE_BUFFER, - g_param_spec_boolean ("double-buffer", "Double-buffer", - "Whether to double-buffer the output", TRUE, G_PARAM_READWRITE)); - - gobject_class->finalize = gst_xvimagesink_finalize; - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state); - - gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps); - gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps); - gstbasesink_class->buffer_alloc = - GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc); - gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times); - gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame); - gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame); -} - -/* ============================================================= */ -/* */ -/* Public Methods */ -/* */ -/* ============================================================= */ - -/* =========================================== */ -/* */ -/* Object typing & Creation */ -/* */ -/* =========================================== */ - -GType -gst_xvimagesink_get_type (void) -{ - static GType xvimagesink_type = 0; - - if (!xvimagesink_type) { - static const GTypeInfo xvimagesink_info = { - sizeof (GstXvImageSinkClass), - gst_xvimagesink_base_init, - NULL, - (GClassInitFunc) gst_xvimagesink_class_init, - NULL, - NULL, - sizeof (GstXvImageSink), - 0, - (GInstanceInitFunc) gst_xvimagesink_init, - }; - static const GInterfaceInfo iface_info = { - (GInterfaceInitFunc) gst_xvimagesink_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo navigation_info = { - (GInterfaceInitFunc) gst_xvimagesink_navigation_init, - NULL, - NULL, - }; - static const GInterfaceInfo overlay_info = { - (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init, - NULL, - NULL, - }; - static const GInterfaceInfo colorbalance_info = { - (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init, - NULL, - NULL, - }; - static const GInterfaceInfo propertyprobe_info = { - (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init, - NULL, - NULL, - }; - xvimagesink_type = g_type_register_static (GST_TYPE_VIDEO_SINK, - "GstXvImageSink", &xvimagesink_info, 0); - - g_type_add_interface_static (xvimagesink_type, - GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info); - g_type_add_interface_static (xvimagesink_type, GST_TYPE_NAVIGATION, - &navigation_info); - g_type_add_interface_static (xvimagesink_type, GST_TYPE_X_OVERLAY, - &overlay_info); - g_type_add_interface_static (xvimagesink_type, GST_TYPE_COLOR_BALANCE, - &colorbalance_info); - g_type_add_interface_static (xvimagesink_type, GST_TYPE_PROPERTY_PROBE, - &propertyprobe_info); - - - /* register type and create class in a more safe place instead of at - * runtime since the type registration and class creation is not - * threadsafe. */ - g_type_class_ref (gst_xvimage_buffer_get_type ()); - } - - return xvimagesink_type; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "xvimagesink", - GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK)) - return FALSE; - - GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0, - "xvimagesink element"); - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "xvimagesink", - "XFree86 video output plugin using Xv extension", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_base/sys/xvimage/xvimagesink.h --- a/gst_plugins_base/sys/xvimage/xvimagesink.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,278 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Julien Moutte - * - * 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. - */ - -#ifndef __GST_XVIMAGESINK_H__ -#define __GST_XVIMAGESINK_H__ - -#include - -#ifdef HAVE_XSHM -#include -#include -#include -#endif /* HAVE_XSHM */ - -#include -#include - -#ifdef HAVE_XSHM -#include -#endif /* HAVE_XSHM */ - -#include -#include - -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_XVIMAGESINK \ - (gst_xvimagesink_get_type()) -#define GST_XVIMAGESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_XVIMAGESINK, GstXvImageSink)) -#define GST_XVIMAGESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_XVIMAGESINK, GstXvImageSinkClass)) -#define GST_IS_XVIMAGESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XVIMAGESINK)) -#define GST_IS_XVIMAGESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XVIMAGESINK)) - -typedef struct _GstXContext GstXContext; -typedef struct _GstXWindow GstXWindow; -typedef struct _GstXvImageFormat GstXvImageFormat; -typedef struct _GstXvImageBuffer GstXvImageBuffer; -typedef struct _GstXvImageBufferClass GstXvImageBufferClass; - -typedef struct _GstXvImageSink GstXvImageSink; -typedef struct _GstXvImageSinkClass GstXvImageSinkClass; - -/** - * GstXContext: - * @disp: the X11 Display of this context - * @screen: the default Screen of Display @disp - * @screen_num: the Screen number of @screen - * @visual: the default Visual of Screen @screen - * @root: the root Window of Display @disp - * @white: the value of a white pixel on Screen @screen - * @black: the value of a black pixel on Screen @screen - * @depth: the color depth of Display @disp - * @bpp: the number of bits per pixel on Display @disp - * @endianness: the endianness of image bytes on Display @disp - * @width: the width in pixels of Display @disp - * @height: the height in pixels of Display @disp - * @widthmm: the width in millimeters of Display @disp - * @heightmm: the height in millimeters of Display @disp - * @par: the pixel aspect ratio calculated from @width, @widthmm and @height, - * @heightmm ratio - * @use_xshm: used to known wether of not XShm extension is usable or not even - * if the Extension is present - * @xv_port_id: the XVideo port ID - * @im_format: used to store at least a valid format for XShm calls checks - * @formats_list: list of supported image formats on @xv_port_id - * @channels_list: list of #GstColorBalanceChannels - * @caps: the #GstCaps that Display @disp can accept - * - * Structure used to store various informations collected/calculated for a - * Display. - */ -struct _GstXContext { - Display *disp; - - Screen *screen; - gint screen_num; - - Visual *visual; - - Window root; - - gulong white, black; - - gint depth; - gint bpp; - gint endianness; - - gint width, height; - gint widthmm, heightmm; - GValue *par; /* calculated pixel aspect ratio */ - - gboolean use_xshm; - - XvPortID xv_port_id; - guint nb_adaptors; - gchar ** adaptors; - gint im_format; - - GList *formats_list; - GList *channels_list; - - GstCaps *caps; - - /* Optimisation storage for buffer_alloc return */ - GstCaps *last_caps; - gint last_format; -}; - -/** - * GstXWindow: - * @win: the Window ID of this X11 window - * @width: the width in pixels of Window @win - * @height: the height in pixels of Window @win - * @internal: used to remember if Window @win was created internally or passed - * through the #GstXOverlay interface - * @gc: the Graphical Context of Window @win - * - * Structure used to store informations about a Window. - */ -struct _GstXWindow { - Window win; - gint width, height; - gboolean internal; - GC gc; -}; - -/** - * GstXvImageFormat: - * @format: the image format - * @caps: generated #GstCaps for this image format - * - * Structure storing image format to #GstCaps association. - */ -struct _GstXvImageFormat { - gint format; - GstCaps *caps; -}; - -/** - * GstXImageBuffer: - * @xvimagesink: a reference to our #GstXvImageSink - * @xvimage: the XvImage of this buffer - * @width: the width in pixels of XvImage @xvimage - * @height: the height in pixels of XvImage @xvimage - * @im_format: the image format of XvImage @xvimage - * @size: the size in bytes of XvImage @xvimage - * - * Subclass of #GstBuffer containing additional information about an XvImage. - */ -struct _GstXvImageBuffer { - GstBuffer buffer; - - /* Reference to the xvimagesink we belong to */ - GstXvImageSink *xvimagesink; - - XvImage *xvimage; - -#ifdef HAVE_XSHM - XShmSegmentInfo SHMInfo; -#endif /* HAVE_XSHM */ - - gint width, height, im_format; - size_t size; -}; - -/** - * GstXvImageSink: - * @display_name: the name of the Display we want to render to - * @xcontext: our instance's #GstXContext - * @xwindow: the #GstXWindow we are rendering to - * @xvimage: internal #GstXvImage used to store incoming buffers and render when - * not using the buffer_alloc optimization mechanism - * @cur_image: a reference to the last #GstXvImage that was put to @xwindow. It - * is used when Expose events are received to redraw the latest video frame - * @event_thread: a thread listening for events on @xwindow and handling them - * @running: used to inform @event_thread if it should run/shutdown - * @fps_n: the framerate fraction numerator - * @fps_d: the framerate fraction denominator - * @x_lock: used to protect X calls as we are not using the XLib in threaded - * mode - * @flow_lock: used to protect data flow routines from external calls such as - * events from @event_thread or methods from the #GstXOverlay interface - * @par: used to override calculated pixel aspect ratio from @xcontext - * @pool_lock: used to protect the buffer pool - * @image_pool: a list of #GstXvImageBuffer that could be reused at next buffer - * allocation call - * @synchronous: used to store if XSynchronous should be used or not (for - * debugging purpose only) - * @keep_aspect: used to remember if reverse negotiation scaling should respect - * aspect ratio - * @handle_events: used to know if we should handle select XEvents or not - * @brightness: used to store the user settings for color balance brightness - * @contrast: used to store the user settings for color balance contrast - * @hue: used to store the user settings for color balance hue - * @saturation: used to store the user settings for color balance saturation - * @cb_changed: used to store if the color balance settings where changed - * @video_width: the width of incoming video frames in pixels - * @video_height: the height of incoming video frames in pixels - * - * The #GstXvImageSink data structure. - */ -struct _GstXvImageSink { - /* Our element stuff */ - GstVideoSink videosink; - - char *display_name; - guint adaptor_no; - - GstXContext *xcontext; - GstXWindow *xwindow; - GstXvImageBuffer *xvimage; - GstXvImageBuffer *cur_image; - - GThread *event_thread; - gboolean running; - - gint fps_n; - gint fps_d; - - GMutex *x_lock; - GMutex *flow_lock; - - /* object-set pixel aspect ratio */ - GValue *par; - - GMutex *pool_lock; - GSList *image_pool; - - gboolean synchronous; - gboolean double_buffer; - gboolean keep_aspect; - gboolean draw_border; - gboolean handle_events; - gboolean handle_expose; - - gint brightness; - gint contrast; - gint hue; - gint saturation; - gboolean cb_changed; - - guint video_width, video_height; /* size of incoming video; - * used as the size for XvImage */ -}; - -struct _GstXvImageSinkClass { - GstVideoSinkClass parent_class; -}; - -GType gst_xvimagesink_get_type(void); - -G_END_DECLS - -#endif /* __GST_XVIMAGESINK_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/bwins/libgstcamerabinu.def --- a/gst_plugins_good/bwins/libgstcamerabinu.def Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -EXPORTS - gst_camerabin_get_type @ 1 NONAME - gst_camerabin_image_get_type @ 2 NONAME - gst_camerabin_video_get_type @ 3 NONAME - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/bwins/libgstphotographyu.def --- a/gst_plugins_good/bwins/libgstphotographyu.def Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -EXPORTS - gst_photography_get_aperture @ 1 NONAME - gst_photography_get_capabilities @ 2 NONAME - gst_photography_get_colour_tone_mode @ 3 NONAME - gst_photography_get_ev_compensation @ 4 NONAME - gst_photography_get_exposure @ 5 NONAME - gst_photography_get_flash_mode @ 6 NONAME - gst_photography_get_iso_speed @ 7 NONAME - gst_photography_get_scene_mode @ 8 NONAME - gst_photography_get_type @ 9 NONAME - gst_photography_get_white_balance_mode @ 10 NONAME - gst_photography_get_zoom @ 11 NONAME - gst_photography_prepare_for_capture @ 12 NONAME - gst_photography_set_aperture @ 13 NONAME - gst_photography_set_autofocus @ 14 NONAME - gst_photography_set_colour_tone_mode @ 15 NONAME - gst_photography_set_ev_compensation @ 16 NONAME - gst_photography_set_exposure @ 17 NONAME - gst_photography_set_flash_mode @ 18 NONAME - gst_photography_set_iso_speed @ 19 NONAME - gst_photography_set_scene_mode @ 20 NONAME - gst_photography_set_white_balance_mode @ 21 NONAME - gst_photography_set_zoom @ 22 NONAME - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/eabi/libgstcamerabinu.def --- a/gst_plugins_good/eabi/libgstcamerabinu.def Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -EXPORTS - gst_camerabin_get_type @ 1 NONAME - gst_camerabin_image_get_type @ 2 NONAME - gst_camerabin_video_get_type @ 3 NONAME - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/eabi/libgstphotographyu.def --- a/gst_plugins_good/eabi/libgstphotographyu.def Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -EXPORTS - gst_photography_get_aperture @ 1 NONAME - gst_photography_get_capabilities @ 2 NONAME - gst_photography_get_colour_tone_mode @ 3 NONAME - gst_photography_get_ev_compensation @ 4 NONAME - gst_photography_get_exposure @ 5 NONAME - gst_photography_get_flash_mode @ 6 NONAME - gst_photography_get_iso_speed @ 7 NONAME - gst_photography_get_scene_mode @ 8 NONAME - gst_photography_get_type @ 9 NONAME - gst_photography_get_white_balance_mode @ 10 NONAME - gst_photography_get_zoom @ 11 NONAME - gst_photography_prepare_for_capture @ 12 NONAME - gst_photography_set_aperture @ 13 NONAME - gst_photography_set_autofocus @ 14 NONAME - gst_photography_set_colour_tone_mode @ 15 NONAME - gst_photography_set_ev_compensation @ 16 NONAME - gst_photography_set_exposure @ 17 NONAME - gst_photography_set_flash_mode @ 18 NONAME - gst_photography_set_iso_speed @ 19 NONAME - gst_photography_set_scene_mode @ 20 NONAME - gst_photography_set_white_balance_mode @ 21 NONAME - gst_photography_set_zoom @ 22 NONAME - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/group/bld.inf --- a/gst_plugins_good/group/bld.inf Fri May 28 18:11:17 2010 -0500 +++ b/gst_plugins_good/group/bld.inf Fri Jun 25 17:18:46 2010 -0500 @@ -2,8 +2,6 @@ default PRJ_EXPORTS -../gst-libs/gst/interfaces/photography.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/photography.h -../gst-libs/gst/interfaces/photography-enumtypes.h /epoc32/include/platform/mw/gstreamer/gst/interfaces/photography-enumtypes.h PRJ_MMPFILES gstwavparse.mmp @@ -11,7 +9,5 @@ gstautodetect.mmp gstavi.mmp gstqtmux.mmp -gstphotography.mmp -gstcamerabin.mmp gstqtdemux.mmp gstmpegaudioparse.mmp diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/group/gstcamerabin.mmp --- a/gst_plugins_good/group/gstcamerabin.mmp Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -// Gstreamer.MMP -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library 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 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - -#include - -TARGET libgstcamerabin.dll -TARGETTYPE DLL -//UID 0x20004c45 0x0DE80A1B -UID 0x20004c45 0x1DE80A1B - -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO HAVE_CONFIG_H - -USERINCLUDE .. -USERINCLUDE ../gst/camerabin -USERINCLUDE ../gst-libs -USERINCLUDE ../gst-libs/gst -USERINCLUDE ../gst-libs/gst/interfaces - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SYSTEMINCLUDE .. - - -SOURCEPATH ../gst/camerabin -SOURCE gstcamerabin.c -SOURCE gstcamerabinxoverlay.c -SOURCE gstcamerabincolorbalance.c -SOURCE camerabinimage.c -SOURCE camerabinvideo.c -SOURCE camerabingeneral.c -SOURCE gstcamerabinphotography.c -SOURCE gstcamerabin-marshal.c - -LIBRARY libc.lib -LIBRARY libpthread.lib -LIBRARY libdl.lib -LIBRARY libglib.lib -LIBRARY libgmodule.lib - -LIBRARY libgobject.lib -LIBRARY libgthread.lib -LIBRARY libm.lib -LIBRARY libz.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib -LIBRARY libgstinterfaces.lib -LIBRARY libgstphotography.lib - -#ifdef WINSCW -LIBRARY ewsd.lib //wsd solution -#endif - - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/group/gstphotography.mmp --- a/gst_plugins_good/group/gstphotography.mmp Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library 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 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - -#include - -TARGET libgstphotography.dll -TARGETTYPE DLL -//UID 0x1000008d 0x10207C43 -// FIX ME change UID -UID 0x1000008d 0x20207C43 - -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO HAVE_CONFIG_H - -USERINCLUDE .. -USERINCLUDE ../gst-libs/gst/interfaces - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE - -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SOURCEPATH ../gst-libs/gst/interfaces -SOURCE photography.c -SOURCE photography-enumtypes.c - - -LIBRARY libc.lib -LIBRARY libpthread.lib -LIBRARY libdl.lib -LIBRARY libglib.lib -LIBRARY libgmodule.lib - -LIBRARY libgobject.lib -LIBRARY libgthread.lib -LIBRARY libgstreamer.lib diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst-libs/gst/interfaces/photography-enumtypes.c --- a/gst_plugins_good/gst-libs/gst/interfaces/photography-enumtypes.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ - -/* Generated data (by glib-mkenums) */ - -#include "photography-enumtypes.h" - -#include "photography.h" - -/* enumerations from "photography.h" */ -GType -gst_white_balance_mode_get_type (void) -{ - static GType etype = 0; - if (etype == 0) { - static const GEnumValue values[] = { - {GST_PHOTOGRAPHY_WB_MODE_AUTO, "GST_PHOTOGRAPHY_WB_MODE_AUTO", "auto"}, - {GST_PHOTOGRAPHY_WB_MODE_DAYLIGHT, "GST_PHOTOGRAPHY_WB_MODE_DAYLIGHT", - "daylight"}, - {GST_PHOTOGRAPHY_WB_MODE_CLOUDY, "GST_PHOTOGRAPHY_WB_MODE_CLOUDY", - "cloudy"}, - {GST_PHOTOGRAPHY_WB_MODE_SUNSET, "GST_PHOTOGRAPHY_WB_MODE_SUNSET", - "sunset"}, - {GST_PHOTOGRAPHY_WB_MODE_TUNGSTEN, "GST_PHOTOGRAPHY_WB_MODE_TUNGSTEN", - "tungsten"}, - {GST_PHOTOGRAPHY_WB_MODE_FLUORESCENT, - "GST_PHOTOGRAPHY_WB_MODE_FLUORESCENT", "fluorescent"}, - {0, NULL, NULL} - }; - etype = g_enum_register_static ("GstWhiteBalanceMode", values); - } - return etype; -} - -GType -gst_colour_tone_mode_get_type (void) -{ - static GType etype = 0; - if (etype == 0) { - static const GEnumValue values[] = { - {GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NORMAL, - "GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NORMAL", "normal"}, - {GST_PHOTOGRAPHY_COLOUR_TONE_MODE_SEPIA, - "GST_PHOTOGRAPHY_COLOUR_TONE_MODE_SEPIA", "sepia"}, - {GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NEGATIVE, - "GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NEGATIVE", "negative"}, - {GST_PHOTOGRAPHY_COLOUR_TONE_MODE_GRAYSCALE, - "GST_PHOTOGRAPHY_COLOUR_TONE_MODE_GRAYSCALE", "grayscale"}, - {GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NATURAL, - "GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NATURAL", "natural"}, - {GST_PHOTOGRAPHY_COLOUR_TONE_MODE_VIVID, - "GST_PHOTOGRAPHY_COLOUR_TONE_MODE_VIVID", "vivid"}, - {GST_PHOTOGRAPHY_COLOUR_TONE_MODE_COLORSWAP, - "GST_PHOTOGRAPHY_COLOUR_TONE_MODE_COLORSWAP", "colorswap"}, - {GST_PHOTOGRAPHY_COLOUR_TONE_MODE_SOLARIZE, - "GST_PHOTOGRAPHY_COLOUR_TONE_MODE_SOLARIZE", "solarize"}, - {GST_PHOTOGRAPHY_COLOUR_TONE_MODE_OUT_OF_FOCUS, - "GST_PHOTOGRAPHY_COLOUR_TONE_MODE_OUT_OF_FOCUS", "out-of-focus"}, - {0, NULL, NULL} - }; - etype = g_enum_register_static ("GstColourToneMode", values); - } - return etype; -} - -GType -gst_scene_mode_get_type (void) -{ - static GType etype = 0; - if (etype == 0) { - static const GEnumValue values[] = { - {GST_PHOTOGRAPHY_SCENE_MODE_MANUAL, "GST_PHOTOGRAPHY_SCENE_MODE_MANUAL", - "manual"}, - {GST_PHOTOGRAPHY_SCENE_MODE_CLOSEUP, "GST_PHOTOGRAPHY_SCENE_MODE_CLOSEUP", - "closeup"}, - {GST_PHOTOGRAPHY_SCENE_MODE_PORTRAIT, - "GST_PHOTOGRAPHY_SCENE_MODE_PORTRAIT", "portrait"}, - {GST_PHOTOGRAPHY_SCENE_MODE_LANDSCAPE, - "GST_PHOTOGRAPHY_SCENE_MODE_LANDSCAPE", "landscape"}, - {GST_PHOTOGRAPHY_SCENE_MODE_SPORT, "GST_PHOTOGRAPHY_SCENE_MODE_SPORT", - "sport"}, - {GST_PHOTOGRAPHY_SCENE_MODE_NIGHT, "GST_PHOTOGRAPHY_SCENE_MODE_NIGHT", - "night"}, - {GST_PHOTOGRAPHY_SCENE_MODE_AUTO, "GST_PHOTOGRAPHY_SCENE_MODE_AUTO", - "auto"}, - {0, NULL, NULL} - }; - etype = g_enum_register_static ("GstSceneMode", values); - } - return etype; -} - -GType -gst_flash_mode_get_type (void) -{ - static GType etype = 0; - if (etype == 0) { - static const GEnumValue values[] = { - {GST_PHOTOGRAPHY_FLASH_MODE_AUTO, "GST_PHOTOGRAPHY_FLASH_MODE_AUTO", - "auto"}, - {GST_PHOTOGRAPHY_FLASH_MODE_OFF, "GST_PHOTOGRAPHY_FLASH_MODE_OFF", "off"}, - {GST_PHOTOGRAPHY_FLASH_MODE_ON, "GST_PHOTOGRAPHY_FLASH_MODE_ON", "on"}, - {GST_PHOTOGRAPHY_FLASH_MODE_FILL_IN, "GST_PHOTOGRAPHY_FLASH_MODE_FILL_IN", - "fill-in"}, - {GST_PHOTOGRAPHY_FLASH_MODE_RED_EYE, "GST_PHOTOGRAPHY_FLASH_MODE_RED_EYE", - "red-eye"}, - {0, NULL, NULL} - }; - etype = g_enum_register_static ("GstFlashMode", values); - } - return etype; -} - -GType -gst_focus_status_get_type (void) -{ - static GType etype = 0; - if (etype == 0) { - static const GEnumValue values[] = { - {GST_PHOTOGRAPHY_FOCUS_STATUS_NONE, "GST_PHOTOGRAPHY_FOCUS_STATUS_NONE", - "none"}, - {GST_PHOTOGRAPHY_FOCUS_STATUS_RUNNING, - "GST_PHOTOGRAPHY_FOCUS_STATUS_RUNNING", "running"}, - {GST_PHOTOGRAPHY_FOCUS_STATUS_FAIL, "GST_PHOTOGRAPHY_FOCUS_STATUS_FAIL", - "fail"}, - {GST_PHOTOGRAPHY_FOCUS_STATUS_SUCCESS, - "GST_PHOTOGRAPHY_FOCUS_STATUS_SUCCESS", "success"}, - {0, NULL, NULL} - }; - etype = g_enum_register_static ("GstFocusStatus", values); - } - return etype; -} - -GType -gst_photo_caps_get_type (void) -{ - static GType etype = 0; - if (etype == 0) { - static const GFlagsValue values[] = { - {GST_PHOTOGRAPHY_CAPS_NONE, "GST_PHOTOGRAPHY_CAPS_NONE", "none"}, - {GST_PHOTOGRAPHY_CAPS_EV_COMP, "GST_PHOTOGRAPHY_CAPS_EV_COMP", "ev-comp"}, - {GST_PHOTOGRAPHY_CAPS_ISO_SPEED, "GST_PHOTOGRAPHY_CAPS_ISO_SPEED", - "iso-speed"}, - {GST_PHOTOGRAPHY_CAPS_WB_MODE, "GST_PHOTOGRAPHY_CAPS_WB_MODE", "wb-mode"}, - {GST_PHOTOGRAPHY_CAPS_TONE, "GST_PHOTOGRAPHY_CAPS_TONE", "tone"}, - {GST_PHOTOGRAPHY_CAPS_SCENE, "GST_PHOTOGRAPHY_CAPS_SCENE", "scene"}, - {GST_PHOTOGRAPHY_CAPS_FLASH, "GST_PHOTOGRAPHY_CAPS_FLASH", "flash"}, - {GST_PHOTOGRAPHY_CAPS_ZOOM, "GST_PHOTOGRAPHY_CAPS_ZOOM", "zoom"}, - {GST_PHOTOGRAPHY_CAPS_FOCUS, "GST_PHOTOGRAPHY_CAPS_FOCUS", "focus"}, - {GST_PHOTOGRAPHY_CAPS_APERTURE, "GST_PHOTOGRAPHY_CAPS_APERTURE", - "aperture"}, - {GST_PHOTOGRAPHY_CAPS_EXPOSURE, "GST_PHOTOGRAPHY_CAPS_EXPOSURE", - "exposure"}, - {GST_PHOTOGRAPHY_CAPS_SHAKE, "GST_PHOTOGRAPHY_CAPS_SHAKE", "shake"}, - {0, NULL, NULL} - }; - etype = g_flags_register_static ("GstPhotoCaps", values); - } - return etype; -} - -GType -gst_photo_shake_risk_get_type (void) -{ - static GType etype = 0; - if (etype == 0) { - static const GEnumValue values[] = { - {GST_PHOTOGRAPHY_SHAKE_RISK_LOW, "GST_PHOTOGRAPHY_SHAKE_RISK_LOW", "low"}, - {GST_PHOTOGRAPHY_SHAKE_RISK_MEDIUM, "GST_PHOTOGRAPHY_SHAKE_RISK_MEDIUM", - "medium"}, - {GST_PHOTOGRAPHY_SHAKE_RISK_HIGH, "GST_PHOTOGRAPHY_SHAKE_RISK_HIGH", - "high"}, - {0, NULL, NULL} - }; - etype = g_enum_register_static ("GstPhotoShakeRisk", values); - } - return etype; -} - -/* Generated data ends here */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst-libs/gst/interfaces/photography-enumtypes.h --- a/gst_plugins_good/gst-libs/gst/interfaces/photography-enumtypes.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ - -/* Generated data (by glib-mkenums) */ - -#ifndef __GST_PHOTOGRAPHY_ENUM_TYPES_H__ -#define __GST_PHOTOGRAPHY_ENUM_TYPES_H__ - -#include - -G_BEGIN_DECLS - -/* enumerations from "photography.h" */ -GType gst_white_balance_mode_get_type (void); -#define GST_TYPE_WHITE_BALANCE_MODE (gst_white_balance_mode_get_type()) -GType gst_colour_tone_mode_get_type (void); -#define GST_TYPE_COLOUR_TONE_MODE (gst_colour_tone_mode_get_type()) -GType gst_scene_mode_get_type (void); -#define GST_TYPE_SCENE_MODE (gst_scene_mode_get_type()) -GType gst_flash_mode_get_type (void); -#define GST_TYPE_FLASH_MODE (gst_flash_mode_get_type()) -GType gst_focus_status_get_type (void); -#define GST_TYPE_FOCUS_STATUS (gst_focus_status_get_type()) -GType gst_photo_caps_get_type (void); -#define GST_TYPE_PHOTO_CAPS (gst_photo_caps_get_type()) -GType gst_photo_shake_risk_get_type (void); -#define GST_TYPE_PHOTO_SHAKE_RISK (gst_photo_shake_risk_get_type()) -G_END_DECLS - -#endif /* __GST_PHOTOGRAPHY_ENUM_TYPES_H__ */ - -/* Generated data ends here */ - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst-libs/gst/interfaces/photography.c --- a/gst_plugins_good/gst-libs/gst/interfaces/photography.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,367 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2008 Nokia Corporation - * - * photography.c: photography interface for digital imaging - * - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "photography.h" - -/** - * SECTION:photography - * @short_description: Interface for elements having digital imaging controls - * - * The interface allows access to some common digital imaging controls - */ - -static void gst_photography_iface_init (GstPhotographyInterface * iface); - -EXPORT_C GType -gst_photography_get_type (void) -{ - static GType gst_photography_type = 0; - - if (!gst_photography_type) { - static const GTypeInfo gst_photography_info = { - sizeof (GstPhotographyInterface), - (GBaseInitFunc) gst_photography_iface_init, - NULL, - NULL, - NULL, - NULL, - 0, - 0, - NULL, - }; - - gst_photography_type = g_type_register_static (G_TYPE_INTERFACE, - "GstPhotography", &gst_photography_info, 0); - g_type_interface_add_prerequisite (gst_photography_type, - GST_TYPE_IMPLEMENTS_INTERFACE); - } - - return gst_photography_type; -} - -static void -gst_photography_iface_init (GstPhotographyInterface * iface) -{ - /* default virtual functions */ - iface->get_ev_compensation = NULL; - iface->get_iso_speed = NULL; - iface->get_aperture = NULL; - iface->get_exposure = NULL; - iface->get_white_balance_mode = NULL; - iface->get_colour_tone_mode = NULL; - iface->get_scene_mode = NULL; - iface->get_flash_mode = NULL; - iface->get_zoom = NULL; - - iface->set_ev_compensation = NULL; - iface->set_iso_speed = NULL; - iface->set_aperture = NULL; - iface->set_exposure = NULL; - iface->set_white_balance_mode = NULL; - iface->set_colour_tone_mode = NULL; - iface->set_scene_mode = NULL; - iface->set_flash_mode = NULL; - iface->set_zoom = NULL; - - iface->get_capabilities = NULL; - iface->prepare_for_capture = NULL; - iface->set_autofocus = NULL; -} - -#define GST_PHOTOGRAPHY_FUNC_TEMPLATE(function_name, param_type) \ -EXPORT_C gboolean \ -gst_photography_set_ ## function_name (GstPhotography * photo, param_type param) \ -{ \ - GstPhotographyInterface *iface; \ - g_return_val_if_fail (photo != NULL, FALSE); \ - iface = GST_PHOTOGRAPHY_GET_IFACE (photo); \ - if (iface->set_ ## function_name) { \ - return iface->set_ ## function_name (photo, param); \ - } \ - return FALSE; \ -} \ -EXPORT_C gboolean \ -gst_photography_get_ ## function_name (GstPhotography * photo, param_type * param) \ -{ \ - GstPhotographyInterface *iface; \ - g_return_val_if_fail (photo != NULL, FALSE); \ - iface = GST_PHOTOGRAPHY_GET_IFACE (photo); \ - if (iface->get_ ## function_name) { \ - return iface->get_ ## function_name (photo, param); \ - } \ - return FALSE; \ -} - - -/** - * gst_photography_set_ev_compensation: - * @photo: #GstPhotography interface of a #GstElement - * @ev_comp: ev compensation value to set - * - * Set the ev compensation value for the #GstElement - * - * Returns: %TRUE if setting the value succeeded, %FALSE otherwise - */ -/** - * gst_photography_get_ev_compensation: - * @photo: #GstPhotography interface of a #GstElement - * @ev_comp: ev compensation value to get - * - * Get the ev compensation value for the #GstElement - * - * Returns: %TRUE if getting the value succeeded, %FALSE otherwise - */ -GST_PHOTOGRAPHY_FUNC_TEMPLATE (ev_compensation, gfloat); - -/** - * gst_photography_set_iso_speed: - * @photo: #GstPhotography interface of a #GstElement - * @iso_speed: ISO speed value to set - * - * Set the ISO value (light sensivity) for the #GstElement - * - * Returns: %TRUE if setting the value succeeded, %FALSE otherwise - */ -/** - * gst_photography_get_iso_speed: - * @photo: #GstPhotography interface of a #GstElement - * @iso_speed: ISO speed value to get - * - * Get the ISO value (light sensivity) for the #GstElement - * - * Returns: %TRUE if getting the value succeeded, %FALSE otherwise - */ -GST_PHOTOGRAPHY_FUNC_TEMPLATE (iso_speed, guint); - -/** - * gst_photography_set_aperture: - * @photo: #GstPhotography interface of a #GstElement - * @aperture: aperture value to set - * - * Set the aperture value for the #GstElement - * - * Returns: %TRUE if setting the value succeeded, %FALSE otherwise - */ -/** - * gst_photography_get_aperture: - * @photo: #GstPhotography interface of a #GstElement - * @aperture: aperture value to get - * - * Get the aperture value for the #GstElement - * - * Returns: %TRUE if getting the value succeeded, %FALSE otherwise - */ -GST_PHOTOGRAPHY_FUNC_TEMPLATE (aperture, guint); - -/** - * gst_photography_set_exposure: - * @photo: #GstPhotography interface of a #GstElement - * @exposure: exposure time to set - * - * Set the fixed exposure time (in us) for the #GstElement - * - * Returns: %TRUE if setting the value succeeded, %FALSE otherwise - */ -/** - * gst_photography_get_exposure: - * @photo: #GstPhotography interface of a #GstElement - * @exposure: exposure time to get - * - * Get the fixed exposure time (in us) for the #GstElement - * - * Returns: %TRUE if getting the value succeeded, %FALSE otherwise - */ -GST_PHOTOGRAPHY_FUNC_TEMPLATE (exposure, guint32); - -/** - * gst_photography_set_white_balance_mode: - * @photo: #GstPhotography interface of a #GstElement - * @wb_mode: #GstWhiteBalanceMode to set - * - * Set the white balance mode for the #GstElement - * - * Returns: %TRUE if setting the value succeeded, %FALSE otherwise - */ -/** - * gst_photography_get_white_balance_mode: - * @photo: #GstPhotography interface of a #GstElement - * @wb_mode: #GstWhiteBalanceMode to get - * - * Get the white balance mode for the #GstElement - * - * Returns: %TRUE if getting the value succeeded, %FALSE otherwise - */ -GST_PHOTOGRAPHY_FUNC_TEMPLATE (white_balance_mode, GstWhiteBalanceMode); - -/** - * gst_photography_set_colour_tone_mode: - * @photo: #GstPhotography interface of a #GstElement - * @tone_mode: #GstColourToneMode to set - * - * Set the colour tone mode for the #GstElement - * - * Returns: %TRUE if setting the value succeeded, %FALSE otherwise - */ -/** - * gst_photography_get_colour_tone_mode: - * @photo: #GstPhotography interface of a #GstElement - * @tone_mode: #GstColourToneMode to get - * - * Get the colour tone mode for the #GstElement - * - * Returns: %TRUE if getting the value succeeded, %FALSE otherwise - */ -GST_PHOTOGRAPHY_FUNC_TEMPLATE (colour_tone_mode, GstColourToneMode); - -/** - * gst_photography_set_scene_mode: - * @photo: #GstPhotography interface of a #GstElement - * @scene_mode: #GstSceneMode to set - * - * Set the scene mode for the #GstElement - * - * Returns: %TRUE if setting the value succeeded, %FALSE otherwise - */ -/** - * gst_photography_get_scene_mode: - * @photo: #GstPhotography interface of a #GstElement - * @scene_mode: #GstSceneMode to get - * - * Get the scene mode for the #GstElement - * - * Returns: %TRUE if getting the value succeeded, %FALSE otherwise - */ -GST_PHOTOGRAPHY_FUNC_TEMPLATE (scene_mode, GstSceneMode); - -/** - * gst_photography_set_flash_mode: - * @photo: #GstPhotography interface of a #GstElement - * @flash_mode: #GstFlashMode to set - * - * Set the flash mode for the #GstElement - * - * Returns: %TRUE if setting the value succeeded, %FALSE otherwise - */ -/** - * gst_photography_get_flash_mode: - * @photo: #GstPhotography interface of a #GstElement - * @flash_mode: #GstFlashMode to get - * - * Get the flash mode for the #GstElement - * - * Returns: %TRUE if getting the value succeeded, %FALSE otherwise - */ -GST_PHOTOGRAPHY_FUNC_TEMPLATE (flash_mode, GstFlashMode); - -/** - * gst_photography_set_zoom: - * @photo: #GstPhotography interface of a #GstElement - * @zoom: zoom value to set - * - * Set the zoom value for the #GstElement. - * E.g. 1.0 to get original image and 3.0 for 3x zoom and so on. - * - * Returns: %TRUE if setting the value succeeded, %FALSE otherwise - */ -/** - * gst_photography_get_zoom: - * @photo: #GstPhotography interface of a #GstElement - * @zoom: zoom value to get - * - * Get the zoom value for the #GstElement - * - * Returns: %TRUE if getting the value succeeded, %FALSE otherwise - */ -GST_PHOTOGRAPHY_FUNC_TEMPLATE (zoom, gfloat); - -/** - * gst_photography_get_capabilities: - * @photo: #GstPhotography interface of a #GstElement - * - * Get #GstPhotoCaps bitmask value that indicates what photography - * interface features the #GstElement supports - * - * Returns: #GstPhotoCaps value - */ -EXPORT_C -GstPhotoCaps -gst_photography_get_capabilities (GstPhotography * photo) -{ - GstPhotographyInterface *iface; - g_return_val_if_fail (photo != NULL, GST_PHOTOGRAPHY_CAPS_NONE); - - iface = GST_PHOTOGRAPHY_GET_IFACE (photo); - if (iface->get_capabilities) { - return iface->get_capabilities (photo); - } else { - return GST_PHOTOGRAPHY_CAPS_NONE; - } -} - -/** - * gst_photography_prepare_for_capture: - * @photo: #GstPhotography interface of a #GstElement - * @func: callback that is called after capturing has been prepared - * @user_data: user data that will be passed to the callback @func - * - * Start preparations for capture. @func callback is called after - * preparations are done. - */ -EXPORT_C -void -gst_photography_prepare_for_capture (GstPhotography * photo, - GstPhotoCapturePrepared func, gpointer user_data) -{ - GstPhotographyInterface *iface; - g_return_if_fail (photo != NULL); - - iface = GST_PHOTOGRAPHY_GET_IFACE (photo); - if (iface->prepare_for_capture) { - iface->prepare_for_capture (photo, func, user_data); - } -} - -/** - * gst_photography_set_autofocus: - * @photo: #GstPhotography interface of a #GstElement - * @on: %TRUE to start autofocusing, %FALSE to stop autofocusing - * - * Start or stop autofocusing. %GST_PHOTOGRAPHY_AUTOFOCUS_DONE - * message is posted to bus when autofocusing has finished. - */ -EXPORT_C -void -gst_photography_set_autofocus (GstPhotography * photo, gboolean on) -{ - GstPhotographyInterface *iface; - g_return_if_fail (photo != NULL); - - iface = GST_PHOTOGRAPHY_GET_IFACE (photo); - if (iface->set_autofocus) { - iface->set_autofocus (photo, on); - } -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst-libs/gst/interfaces/photography.h --- a/gst_plugins_good/gst-libs/gst/interfaces/photography.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2008 Nokia Corporation - * - * photography.h: photography interface for digital imaging - * - * - * 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. - */ - -#ifndef __GST_PHOTOGRAPHY_H__ -#define __GST_PHOTOGRAPHY_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_PHOTOGRAPHY \ - (gst_photography_get_type ()) -#define GST_PHOTOGRAPHY(obj) \ - (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PHOTOGRAPHY, GstPhotography)) -#define GST_IS_PHOTOGRAPHY(obj) \ - (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PHOTOGRAPHY)) -#define GST_PHOTOGRAPHY_GET_IFACE(inst) \ - (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_PHOTOGRAPHY, GstPhotographyInterface)) - - -/* Custom GstMessage name that will be sent to GstBus when autofocusing - is complete */ -#define GST_PHOTOGRAPHY_AUTOFOCUS_DONE "autofocus-done" - -/* Custom GstMessage name that will be sent to GstBus when shake risk changes */ -#define GST_PHOTOGRAPHY_SHAKE_RISK "shake-risk" - -/** - * GstPhotography: - * - * Opaque #GstPhotography data structure. - */ -typedef struct _GstPhotography GstPhotography; - -typedef enum -{ - GST_PHOTOGRAPHY_WB_MODE_AUTO = 0, - GST_PHOTOGRAPHY_WB_MODE_DAYLIGHT, - GST_PHOTOGRAPHY_WB_MODE_CLOUDY, - GST_PHOTOGRAPHY_WB_MODE_SUNSET, - GST_PHOTOGRAPHY_WB_MODE_TUNGSTEN, - GST_PHOTOGRAPHY_WB_MODE_FLUORESCENT -} GstWhiteBalanceMode; - -typedef enum -{ - GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NORMAL = 0, - GST_PHOTOGRAPHY_COLOUR_TONE_MODE_SEPIA, - GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NEGATIVE, - GST_PHOTOGRAPHY_COLOUR_TONE_MODE_GRAYSCALE, - GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NATURAL, - GST_PHOTOGRAPHY_COLOUR_TONE_MODE_VIVID, - GST_PHOTOGRAPHY_COLOUR_TONE_MODE_COLORSWAP, - GST_PHOTOGRAPHY_COLOUR_TONE_MODE_SOLARIZE, - GST_PHOTOGRAPHY_COLOUR_TONE_MODE_OUT_OF_FOCUS -} GstColourToneMode; - -typedef enum -{ - GST_PHOTOGRAPHY_SCENE_MODE_MANUAL = 0, - GST_PHOTOGRAPHY_SCENE_MODE_CLOSEUP, - GST_PHOTOGRAPHY_SCENE_MODE_PORTRAIT, - GST_PHOTOGRAPHY_SCENE_MODE_LANDSCAPE, - GST_PHOTOGRAPHY_SCENE_MODE_SPORT, - GST_PHOTOGRAPHY_SCENE_MODE_NIGHT, - GST_PHOTOGRAPHY_SCENE_MODE_AUTO -} GstSceneMode; - -typedef enum -{ - GST_PHOTOGRAPHY_FLASH_MODE_AUTO = 0, - GST_PHOTOGRAPHY_FLASH_MODE_OFF, - GST_PHOTOGRAPHY_FLASH_MODE_ON, - GST_PHOTOGRAPHY_FLASH_MODE_FILL_IN, - GST_PHOTOGRAPHY_FLASH_MODE_RED_EYE -} GstFlashMode; - -typedef enum -{ - GST_PHOTOGRAPHY_FOCUS_STATUS_NONE = 0, - GST_PHOTOGRAPHY_FOCUS_STATUS_RUNNING, - GST_PHOTOGRAPHY_FOCUS_STATUS_FAIL, - GST_PHOTOGRAPHY_FOCUS_STATUS_SUCCESS -} GstFocusStatus; - -typedef enum -{ - GST_PHOTOGRAPHY_CAPS_NONE = (0 << 0), - GST_PHOTOGRAPHY_CAPS_EV_COMP = (1 << 0), - GST_PHOTOGRAPHY_CAPS_ISO_SPEED = (1 << 1), - GST_PHOTOGRAPHY_CAPS_WB_MODE = (1 << 2), - GST_PHOTOGRAPHY_CAPS_TONE = (1 << 3), - GST_PHOTOGRAPHY_CAPS_SCENE = (1 << 4), - GST_PHOTOGRAPHY_CAPS_FLASH = (1 << 5), - GST_PHOTOGRAPHY_CAPS_ZOOM = (1 << 6), - GST_PHOTOGRAPHY_CAPS_FOCUS = (1 << 7), - GST_PHOTOGRAPHY_CAPS_APERTURE = (1 << 8), - GST_PHOTOGRAPHY_CAPS_EXPOSURE = (1 << 9), - GST_PHOTOGRAPHY_CAPS_SHAKE = (1 << 10) -} GstPhotoCaps; - -typedef enum -{ - GST_PHOTOGRAPHY_SHAKE_RISK_LOW = 0, - GST_PHOTOGRAPHY_SHAKE_RISK_MEDIUM, - GST_PHOTOGRAPHY_SHAKE_RISK_HIGH, -} GstPhotoShakeRisk; - -typedef struct -{ - GstWhiteBalanceMode wb_mode; - GstColourToneMode tone_mode; - GstSceneMode scene_mode; - GstFlashMode flash_mode; - guint32 exposure; - guint aperture; - gfloat ev_compensation; - guint iso_speed; - gfloat zoom; -} GstPhotoSettings; - -/** - * GstPhotoCapturePrepared: - * @data: user data that has been given, when registering the callback - * - * This callback will be called when the element has finished preparations - * for photo capture. - */ -typedef void (*GstPhotoCapturePrepared) (gpointer data); - -/** - * GstPhotographyInterface: - * @parent: parent interface type. - * @get_ev_compensation: vmethod to get ev exposure compensation value - * @get_iso_speed: vmethod to get iso speed (light sensitivity) value - * @get_aperture: vmethod to get aperture value - * @get_exposure: vmethod to get exposure time value - * @get_white_balance_mode: vmethod to get white balance mode value - * @get_colour_tone_mode: vmethod to get colour tone mode value - * @get_scene_mode: vmethod to get scene mode value - * @get_flash_mode: vmethod to get flash mode value - * @get_zoom: vmethod to get zoom factor value - * @set_ev_compensation: vmethod to set ev exposure compensation value - * @set_iso_speed: vmethod to set iso speed (light sensitivity) value - * @set_aperture: vmethod to set aperture value - * @set_exposure: vmethod to set exposure time value - * @set_white_balance_mode: vmethod to set white balance mode value - * @set_colour_tone_mode: vmethod to set colour tone mode value - * @set_scene_mode: vmethod to set scene mode value - * @set_flash_mode: vmethod to set flash mode value - * @set_zoom: vmethod to set zoom factor value - * @get_capabilities: vmethod to get supported capabilities of the interface - * @prepare_for_capture: vmethod to tell the element to prepare for capturing - * @set_autofocus: vmethod to set autofocus on/off - * - * #GstPhotographyInterface interface. - */ -typedef struct _GstPhotographyInterface -{ - GTypeInterface parent; - - /* virtual functions */ - gboolean (*get_ev_compensation) (GstPhotography * photo, gfloat * ev_comp); - gboolean (*get_iso_speed) (GstPhotography * photo, guint * iso_speed); - gboolean (*get_aperture) (GstPhotography * photo, guint * aperture); - gboolean (*get_exposure) (GstPhotography * photo, guint32 * exposure); - gboolean (*get_white_balance_mode) (GstPhotography * photo, - GstWhiteBalanceMode * wb_mode); - gboolean (*get_colour_tone_mode) (GstPhotography * photo, - GstColourToneMode * tone_mode); - gboolean (*get_scene_mode) (GstPhotography * photo, - GstSceneMode * scene_mode); - gboolean (*get_flash_mode) (GstPhotography * photo, - GstFlashMode * flash_mode); - gboolean (*get_zoom) (GstPhotography * photo, gfloat * zoom); - - gboolean (*set_ev_compensation) (GstPhotography * photo, gfloat ev_comp); - gboolean (*set_iso_speed) (GstPhotography * photo, guint iso_speed); - gboolean (*set_aperture) (GstPhotography * photo, guint aperture); - gboolean (*set_exposure) (GstPhotography * photo, guint32 exposure); - gboolean (*set_white_balance_mode) (GstPhotography * photo, - GstWhiteBalanceMode wb_mode); - gboolean (*set_colour_tone_mode) (GstPhotography * photo, - GstColourToneMode tone_mode); - gboolean (*set_scene_mode) (GstPhotography * photo, - GstSceneMode scene_mode); - gboolean (*set_flash_mode) (GstPhotography * photo, - GstFlashMode flash_mode); - gboolean (*set_zoom) (GstPhotography * photo, gfloat zoom); - - GstPhotoCaps (*get_capabilities) (GstPhotography * photo); - void (*prepare_for_capture) (GstPhotography * photo, - GstPhotoCapturePrepared func, gpointer user_data); - void (*set_autofocus) (GstPhotography * photo, gboolean on); - - /*< private > */ - gpointer _gst_reserved[GST_PADDING]; -} GstPhotographyInterface; - -IMPORT_C GType gst_photography_get_type (void); - -/* virtual class function wrappers */ -IMPORT_C gboolean gst_photography_get_ev_compensation (GstPhotography * photo, - gfloat * ev_comp); -IMPORT_C gboolean gst_photography_get_iso_speed (GstPhotography * photo, - guint * iso_speed); -IMPORT_C gboolean gst_photography_get_aperture (GstPhotography * photo, - guint * aperture); -IMPORT_C gboolean gst_photography_get_exposure (GstPhotography * photo, - guint32 * exposure); -IMPORT_C gboolean gst_photography_get_white_balance_mode (GstPhotography * photo, - GstWhiteBalanceMode * wb_mode); -IMPORT_C gboolean gst_photography_get_colour_tone_mode (GstPhotography * photo, - GstColourToneMode * tone_mode); -IMPORT_C gboolean gst_photography_get_scene_mode (GstPhotography * photo, - GstSceneMode * scene_mode); -IMPORT_C gboolean gst_photography_get_flash_mode (GstPhotography * photo, - GstFlashMode * flash_mode); -IMPORT_C gboolean gst_photography_get_zoom (GstPhotography * photo, gfloat * zoom); - -IMPORT_C gboolean gst_photography_set_ev_compensation (GstPhotography * photo, - gfloat ev_comp); -IMPORT_C gboolean gst_photography_set_iso_speed (GstPhotography * photo, - guint iso_speed); -IMPORT_C gboolean gst_photography_set_aperture (GstPhotography * photo, guint aperture); -IMPORT_C gboolean gst_photography_set_exposure (GstPhotography * photo, guint exposure); -IMPORT_C gboolean gst_photography_set_white_balance_mode (GstPhotography * photo, - GstWhiteBalanceMode wb_mode); -IMPORT_C gboolean gst_photography_set_colour_tone_mode (GstPhotography * photo, - GstColourToneMode tone_mode); -IMPORT_C gboolean gst_photography_set_scene_mode (GstPhotography * photo, - GstSceneMode scene_mode); -IMPORT_C gboolean gst_photography_set_flash_mode (GstPhotography * photo, - GstFlashMode flash_mode); -IMPORT_C gboolean gst_photography_set_zoom (GstPhotography * photo, gfloat zoom); - -IMPORT_C GstPhotoCaps gst_photography_get_capabilities (GstPhotography * photo); - -IMPORT_C void gst_photography_prepare_for_capture (GstPhotography * photo, - GstPhotoCapturePrepared func, gpointer user_data); - -IMPORT_C void gst_photography_set_autofocus (GstPhotography * photo, gboolean on); - -G_END_DECLS - -#endif /* __GST_PHOTOGRAPHY_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/amrmux/gstamrmux.c --- a/gst_plugins_good/gst/amrmux/gstamrmux.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,321 +0,0 @@ -/* - * Copyright © 2010 Nokia Corporation. - * This material, including documentation and any related - * computer progrs, is protected by copyright controlled by - * Nokia Corporation. All rights are reserved. Copying, - * including reproducing, storing, adapting or translating, any - * or all of this material requires the prior written consent of - * Nokia Corporation. This material also contains confidential - * information which may not be disclosed to others without the - * prior written consent of Nokia Corporation. - * ============================================================================ - */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - - -#include "gstamrmux.h" - -#include -#include - - -#ifdef __SYMBIAN32__ -#include -#endif - -/* AMR nb header value */ -const char* amrnbmagicnumber = "#!AMR\n"; - -static void gst_amrmux_base_init (gpointer g_class); -static void gst_amrmux_class_init (GstAmrMuxClass * klass); -static void gst_amrmux_init ( GstAmrMux * filter, GstAmrMuxClass *filter_klass); - -static GstFlowReturn gst_amrmux_chain (GstPad * pad, GstBuffer * buf); - -static void gst_amrmux_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static void gst_amrmux_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec); - -static GstStateChangeReturn gst_amrmux_change_state (GstElement * element, - GstStateChange transition); - -static void gst_amrmux_dispose(GObject * object); - -static GstElementClass *parent_class= NULL; - -static const GstElementDetails gst_amrmux_details = -GST_ELEMENT_DETAILS ("AMR MUX Details", - "Codec/Muxer/Audio", - "Adaptive Multi-Rate Narrow-Band Muxer", - ""); - -static GstStaticPadTemplate sink_factory = -GST_STATIC_PAD_TEMPLATE ( - "sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/amr") -); - -static GstStaticPadTemplate source_factory = -GST_STATIC_PAD_TEMPLATE ( - "src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/amr") -); - -enum { - ARG_0, - ARG_HEADER -}; - - -GType -gst_amrmux_get_type (void) -{ - static GType gst_amrmux_type = 0; - - if (!gst_amrmux_type) { - static const GTypeInfo amrmux_info = { - sizeof (GstAmrMuxClass), - gst_amrmux_base_init, - NULL, - (GClassInitFunc) gst_amrmux_class_init, - NULL, - NULL, - sizeof (GstAmrMux), - 0, - (GInstanceInitFunc) gst_amrmux_init, - }; - - gst_amrmux_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstAmrMux", - &amrmux_info, 0); - } - return gst_amrmux_type; -} - - -static void -gst_amrmux_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template(element_class, - gst_static_pad_template_get(&sink_factory)); - - gst_element_class_add_pad_template(element_class, - gst_static_pad_template_get(&source_factory)); - - gst_element_class_set_details (element_class, &gst_amrmux_details); -} - -static void -gst_amrmux_class_init ( GstAmrMuxClass * klass ) -{ - GObjectClass *object_class; - GstElementClass *gstelement_class; - - gstelement_class = (GstElementClass *) klass; - object_class = (GObjectClass *) klass; - - - object_class->set_property = gst_amrmux_set_property; - object_class->get_property = gst_amrmux_get_property; - - gstelement_class->change_state = gst_amrmux_change_state; - - object_class->dispose = gst_amrmux_dispose; - - parent_class = g_type_class_peek_parent(klass); - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HEADER, - g_param_spec_boolean ("header", "header", - "For writing AMR header", TRUE, G_PARAM_READWRITE)); - - - } - -static void gst_amrmux_dispose(GObject * object) -{ - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gst_amrmux_init( GstAmrMux * amrmux, GstAmrMuxClass *amrmux_klass) -{ - GstElementClass *klass = GST_ELEMENT_CLASS (amrmux_klass); - - //By default we have to write header - amrmux->writeheader= TRUE; - - //Add Sink pad to this element - - amrmux->sinkpad = gst_pad_new_from_template ( - gst_element_class_get_pad_template (klass, "sink"), "sink"); - - gst_element_add_pad (GST_ELEMENT (amrmux), amrmux->sinkpad); - - - //Add Src pad to this element - amrmux->srcpad = gst_pad_new_from_template ( - gst_element_class_get_pad_template (klass, "src"), "src"); - - gst_element_add_pad (GST_ELEMENT (amrmux), amrmux->srcpad); - - gst_pad_set_chain_function (amrmux->sinkpad, gst_amrmux_chain); - -} - - -static void -gst_amrmux_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - - GstAmrMux *amrmux = GST_AMRMUX( object ); - - switch (prop_id) { - case ARG_HEADER: - g_value_set_boolean (value, amrmux->writeheader); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -gst_amrmux_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ -GstAmrMux *amrmux = GST_AMRMUX( object ); - - switch (prop_id) { - case ARG_HEADER: - amrmux->writeheader = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - - -static GstFlowReturn -gst_amrmux_chain (GstPad * pad, GstBuffer * buf) -{ - - gint8 *codecdata; - guint8* amrdata; - guint8* amrheaderstart; - - int codecdatasize = GST_BUFFER_SIZE(buf); - - int magicnumberlength = strlen( amrnbmagicnumber ); - - GstAmrMux *amrmux = GST_AMRMUX (GST_PAD_PARENT (pad)); - - if ( amrmux->writeheader ) - { - - buf = gst_buffer_make_writable( buf ); - - //Allocate a buffer which will hold codec data + magic number - - amrdata = ( guint8* )g_malloc( GST_BUFFER_SIZE(buf) + magicnumberlength ); - - //To save the starting address of amr data - - amrheaderstart = amrdata; - - //Copy magic number to newly allocated buffer - - memcpy( amrdata, amrnbmagicnumber, magicnumberlength); - - codecdata = (gint8*)GST_BUFFER_DATA (buf); - - //Move the pointer to the end of magic number - - amrdata += magicnumberlength; - - //Copy codec data to newly allocated buffer - - memcpy( amrdata , codecdata, codecdatasize ); - - // free codec data from GstBuffer - - g_free( buf->malloc_data ); - - //Copying the newly allocated buffer and size in GstBuffer - - buf->data = amrheaderstart; - - buf->malloc_data = amrheaderstart; - - buf->size+= magicnumberlength; - - //Do it only first time - - amrmux->writeheader = FALSE; - } - - return gst_pad_push( amrmux->srcpad , buf ); - -} - -static GstStateChangeReturn -gst_amrmux_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - GstAmrMux *amrmux = GST_AMRMUX (element); - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - if (G_UNLIKELY (ret == GST_STATE_CHANGE_FAILURE)) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - { - amrmux->writeheader = TRUE; - break; - } - - default: - break; - } - - return ret; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - - return gst_element_register (plugin, "amrmux", GST_RANK_PRIMARY, - GST_TYPE_AMRMUX); -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "amrmux", - "Add header to amr-nb encoded stream", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) - - -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/amrmux/gstamrmux.h --- a/gst_plugins_good/gst/amrmux/gstamrmux.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright © 2010 Nokia Corporation. - * This material, including documentation and any related - * computer progrs, is protected by copyright controlled by - * Nokia Corporation. All rights are reserved. Copying, - * including reproducing, storing, adapting or translating, any - * or all of this material requires the prior written consent of - * Nokia Corporation. This material also contains confidential - * information which may not be disclosed to others without the - * prior written consent of Nokia Corporation. - * ============================================================================ - */ - - -#ifndef __GST_AMRMUX_H__ -#define __GST_AMRMUX_H__ - - -#include -#include - - -G_BEGIN_DECLS - -#define GST_TYPE_AMRMUX \ - (gst_amrmux_get_type()) -#define GST_AMRMUX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AMRMUX,GstAmrMux)) -#define GST_AMRMUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AMRMUX,GstAmrMuxClass)) -#define GST_IS_AMRMUX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AMRMUX)) -#define GST_IS_AMRMUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AMRMUX)) - - -typedef struct _GstAmrMux GstAmrMux; -typedef struct _GstAmrMuxClass GstAmrMuxClass; - -/** - * GstAmrMux: - * - * - */ -struct _GstAmrMux { - GstElement parent; - - /* pads */ - GstPad *sinkpad,*srcpad; - - /* Flag to decide whether to write amr header or not */ - gboolean writeheader; -}; - -struct _GstAmrMuxClass { - GstElementClass parent_class; -}; - -GType gst_amrmux_get_type(void); - -G_END_DECLS - -#endif /* __GST_AMRMUX_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/amrmux/gstamrmux.mmp --- a/gst_plugins_good/gst/amrmux/gstamrmux.mmp Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright © 2010 Nokia Corporation. - * This material, including documentation and any related - * computer progrs, is protected by copyright controlled by - * Nokia Corporation. All rights are reserved. Copying, - * including reproducing, storing, adapting or translating, any - * or all of this material requires the prior written consent of - * Nokia Corporation. This material also contains confidential - * information which may not be disclosed to others without the - * prior written consent of Nokia Corporation. - * ============================================================================ - */ - -#include - -TARGET libgstamrmux.dll -TARGETTYPE DLL -UID 0x2002C38F 0x2002C390 - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT - -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO HAVE_CONFIG_H - - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE - - -USERINCLUDE ../../../include/gstreamer -USERINCLUDE ../../../include/gstreamer/gst -USERINCLUDE ../../../include/gstreamer/gst/base -USERINCLUDE ../../../include/gstreamer/gst/controller -USERINCLUDE ../../../include/gstreamer/gst/dataprotocol -USERINCLUDE ../../../include/gstreamer/gst/net - - - -SOURCEPATH ../gst/amrmux -SOURCE gstamrmux.c - - -LIBRARY libc.lib -LIBRARY libglib.lib -LIBRARY libgmodule.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/camerabingeneral.c --- a/gst_plugins_good/gst/camerabin/camerabingeneral.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,263 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -/** - * SECTION:camerabingeneral - * @short_description: helper functions for #GstCameraBin and it's modules - * - * Common helper functions for #GstCameraBin, #GstCameraBinImage and - * #GstCameraBinVideo. - * - */ - -#include "camerabingeneral.h" -#include - -GST_DEBUG_CATEGORY (gst_camerabin_debug); - -static gboolean -camerabin_general_dbg_have_event (GstPad * pad, GstEvent * event, - gpointer u_data) -{ - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - { - GstElement *elem = (GstElement *) u_data; - gchar *elem_name = gst_element_get_name (elem); - gchar *pad_name = gst_pad_get_name (pad); - - gboolean update; - gdouble rate; - GstFormat format; - gint64 start, stop, pos; - gst_event_parse_new_segment (event, &update, &rate, &format, &start, - &stop, &pos); - - GST_DEBUG ("element %s, pad %s, new_seg_start =%" GST_TIME_FORMAT - ", new_seg_stop =%" GST_TIME_FORMAT - ", new_seg_pos =%" GST_TIME_FORMAT "\n", elem_name, pad_name, - GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (pos)); - - g_free (pad_name); - g_free (elem_name); - } - break; - default: - break; - } - - return TRUE; -} - -static gboolean -camerabin_general_dbg_have_buffer (GstPad * pad, GstBuffer * buffer, - gpointer u_data) -{ - GstElement *elem = (GstElement *) u_data; - gchar *elem_name = gst_element_get_name (elem); - gchar *pad_name = gst_pad_get_name (pad); - - GST_DEBUG ("element %s, pad %s, buf_ts =%" GST_TIME_FORMAT "\n", elem_name, - pad_name, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); - - g_free (pad_name); - g_free (elem_name); - - return TRUE; - -} - -void -camerabin_general_dbg_set_probe (GstElement * elem, gchar * pad_name, - gboolean buf, gboolean evt) -{ - GstPad *pad = gst_element_get_static_pad (elem, pad_name); - - if (buf) - gst_pad_add_buffer_probe (pad, - G_CALLBACK (camerabin_general_dbg_have_buffer), elem); - if (evt) - gst_pad_add_event_probe (pad, - G_CALLBACK (camerabin_general_dbg_have_event), elem); - - gst_object_unref (pad); -} - -/** - * gst_camerabin_add_element: - * @bin: add an element to this bin - * @new_elem: new element to be added - * - * Adds given element to given @bin. Looks for an unconnected src pad - * from the @bin and links the element to it. Raises an error if adding - * or linking failed. - * - * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise. - */ -gboolean -gst_camerabin_add_element (GstBin * bin, GstElement * new_elem) -{ - gboolean ret = FALSE; - - ret = gst_camerabin_try_add_element (bin, new_elem); - - if (!ret) { - gchar *elem_name = gst_element_get_name (new_elem); - GST_ELEMENT_ERROR (bin, CORE, NEGOTIATION, (NULL), - ("linking %s failed", elem_name)); - g_free (elem_name); - } - - return ret; -} - -/** - * gst_camerabin_try_add_element: - * @bin: tries adding an element to this bin - * @new_elem: new element to be added - * - * Adds given element to given @bin. Looks for an unconnected src pad - * from the @bin and links the element to it. - * - * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise. - */ -gboolean -gst_camerabin_try_add_element (GstBin * bin, GstElement * new_elem) -{ - GstPad *bin_pad; - GstElement *bin_elem; - gboolean ret = TRUE; - - if (!bin || !new_elem) { - return FALSE; - } - - /* Get pads for linking */ - GST_DEBUG ("finding unconnected src pad"); - //bin_pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC); - bin_pad = gst_bin_find_unconnected_pad (bin, GST_PAD_SRC); - GST_DEBUG ("unconnected pad %s:%s", GST_DEBUG_PAD_NAME (bin_pad)); - /* Add to bin */ - gst_bin_add (GST_BIN (bin), new_elem); - /* Link, if unconnected pad was found, otherwise just add it to bin */ - if (bin_pad) { - bin_elem = gst_pad_get_parent_element (bin_pad); - gst_object_unref (bin_pad); - if (!gst_element_link (bin_elem, new_elem)) { - gst_bin_remove (bin, new_elem); - ret = FALSE; - } - gst_object_unref (bin_elem); - } - - return ret; -} - -/** - * gst_camerabin_create_and_add_element: - * @bin: tries adding an element to this bin - * @elem_name: name of the element to be created - * - * Creates an element according to given name and - * adds it to given @bin. Looks for an unconnected src pad - * from the @bin and links the element to it. - * - * Returns: pointer to the new element if successful, NULL otherwise. - */ -GstElement * -gst_camerabin_create_and_add_element (GstBin * bin, const gchar * elem_name) -{ - GstElement *new_elem = NULL; - - GST_DEBUG ("adding %s", elem_name); - new_elem = gst_element_factory_make (elem_name, NULL); - if (!new_elem) { - GST_ELEMENT_ERROR (bin, CORE, MISSING_PLUGIN, (NULL), - ("could not create \"%s\" element.", elem_name)); - } else if (!gst_camerabin_add_element (bin, new_elem)) { - new_elem = NULL; - } - - return new_elem; -} - -/** - * gst_camerabin_remove_elements_from_bin: - * @bin: removes all elements from this bin - * - * Removes all elements from this @bin. - */ -void -gst_camerabin_remove_elements_from_bin (GstBin * bin) -{ - GstIterator *iter = NULL; - gpointer data = NULL; - GstElement *elem = NULL; - gboolean done = FALSE; - - iter = gst_bin_iterate_elements (bin); - while (!done) { - switch (gst_iterator_next (iter, &data)) { - case GST_ITERATOR_OK: - elem = GST_ELEMENT (data); - gst_bin_remove (bin, elem); - /* Iterator increased the element refcount, so unref */ - gst_object_unref (elem); - break; - case GST_ITERATOR_RESYNC: - gst_iterator_resync (iter); - break; - case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (bin, "error in iterating elements"); - done = TRUE; - break; - case GST_ITERATOR_DONE: - done = TRUE; - break; - } - } - gst_iterator_free (iter); -} - -/** - * gst_camerabin_drop_eos_probe: - * @pad: pad receiving the event - * @event: received event - * @u_data: not used - * - * Event probe that drop all eos events. - * - * Returns: FALSE to drop the event, TRUE otherwise - */ -gboolean -gst_camerabin_drop_eos_probe (GstPad * pad, GstEvent * event, gpointer u_data) -{ - gboolean ret = TRUE; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - GST_DEBUG ("dropping eos in %s:%s", GST_DEBUG_PAD_NAME (pad)); - ret = FALSE; - break; - default: - break; - } - return ret; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/camerabingeneral.h --- a/gst_plugins_good/gst/camerabin/camerabingeneral.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -#ifndef __CAMERABIN_GENERAL_H_ -#define __CAMERABIN_GENERAL_H_ - -#include -#include - -#include - - -typedef struct timeval TIME_TYPE; -#define GET_TIME(t) do { gettimeofday(&(t), NULL); } while(0) -#define DIFF_TIME(t2,t1,d) do { d = ((t2).tv_sec - (t1).tv_sec) * 1000000 + \ - (t2).tv_usec - (t1).tv_usec; } while(0) - -#define _INIT_TIMER_BLOCK TIME_TYPE t1, t2; guint32 d; do {;}while (0) - -#define _OPEN_TIMER_BLOCK { GET_TIME(t1); do {;}while (0) -#define _CLOSE_TIMER_BLOCK GET_TIME(t2); DIFF_TIME(t2,t1,d); \ - GST_DEBUG("elapsed time = %u\n", d); \ - } do {;}while (0) - - -extern void -camerabin_general_dbg_set_probe (GstElement * elem, gchar * pad_name, - gboolean buf, gboolean evt); - -gboolean gst_camerabin_try_add_element (GstBin * bin, GstElement * new_elem); - -gboolean gst_camerabin_add_element (GstBin * bin, GstElement * new_elem); - -GstElement *gst_camerabin_create_and_add_element (GstBin * bin, - const gchar * elem_name); - -void gst_camerabin_remove_elements_from_bin (GstBin * bin); - -gboolean -gst_camerabin_drop_eos_probe (GstPad * pad, GstEvent * event, gpointer u_data); - -GST_DEBUG_CATEGORY_EXTERN (gst_camerabin_debug); -#define GST_CAT_DEFAULT gst_camerabin_debug - -#endif /* #ifndef __CAMERABIN_GENERAL_H_ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/camerabinimage.c --- a/gst_plugins_good/gst/camerabin/camerabinimage.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,571 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -/** - * SECTION:camerabinimage - * @short_description: image capturing module of #GstCameraBin - * - * - * - * - * The pipeline for this module is: - * - * - * - *----------------------------------------------------------------------------- - * (src0) -> queue -> - * -> [post proc] -> tee < - * (src1) -> imageenc -> metadatamuxer -> filesink - *----------------------------------------------------------------------------- - * - * - * - * The property of elements are: - * - * queue - "max-size-buffers", 1, "leaky", 2, - * - * The image bin opens file for image writing in READY to PAUSED state change. - * The image bin closes the file in PAUSED to READY state change. - * - * - * - */ - -/* - * includes - */ - -#include - -#include "camerabinimage.h" -#include "camerabingeneral.h" - -#include "string.h" - -/* default internal element names */ - -#define DEFAULT_SINK "filesink" -#define DEFAULT_ENC "jpegenc" -#define DEFAULT_META_MUX "metadatamux" - -enum -{ - PROP_0, - PROP_FILENAME -}; - -static gboolean gst_camerabin_image_create_elements (GstCameraBinImage * img); -static void gst_camerabin_image_destroy_elements (GstCameraBinImage * img); - -static void gst_camerabin_image_dispose (GstCameraBinImage * sink); -static GstStateChangeReturn -gst_camerabin_image_change_state (GstElement * element, - GstStateChange transition); -static gboolean gst_camerabin_image_send_event (GstElement * element, - GstEvent * event); -static void gst_camerabin_image_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_camerabin_image_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -GST_BOILERPLATE (GstCameraBinImage, gst_camerabin_image, GstBin, GST_TYPE_BIN); - -static const GstElementDetails gst_camerabin_image_details = -GST_ELEMENT_DETAILS ("Image capture bin for camerabin", - "Bin/Image", - "Process and store image data", - "Edgard Lima \n" - "Nokia Corporation "); - -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static void -gst_camerabin_image_base_init (gpointer klass) -{ - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (eklass, - gst_static_pad_template_get (&sink_template)); - gst_element_class_add_pad_template (eklass, - gst_static_pad_template_get (&src_template)); - gst_element_class_set_details (eklass, &gst_camerabin_image_details); -} - -static void -gst_camerabin_image_class_init (GstCameraBinImageClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - - gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = - (GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_camerabin_image_dispose); - eklass->change_state = GST_DEBUG_FUNCPTR (gst_camerabin_image_change_state); - eklass->send_event = GST_DEBUG_FUNCPTR (gst_camerabin_image_send_event); - - gobject_class->set_property = - GST_DEBUG_FUNCPTR (gst_camerabin_image_set_property); - gobject_class->get_property = - GST_DEBUG_FUNCPTR (gst_camerabin_image_get_property); - - /** - * GstCameraBinImage:filename - * - * This property can be used to specify the filename of the image. - * - **/ - g_object_class_install_property (gobject_class, PROP_FILENAME, - g_param_spec_string ("filename", "Filename", - "Filename of the image to save", NULL, G_PARAM_READWRITE)); -} - -static void -gst_camerabin_image_init (GstCameraBinImage * img, - GstCameraBinImageClass * g_class) -{ - img->filename = g_string_new (""); - - img->pad_tee_enc = NULL; - img->pad_tee_view = NULL; - - img->post = NULL; - img->tee = NULL; - img->enc = NULL; - img->user_enc = NULL; - img->meta_mux = NULL; - img->sink = NULL; - img->queue = NULL; - - /* Create src and sink ghost pads */ - img->sinkpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK); - gst_element_add_pad (GST_ELEMENT (img), img->sinkpad); - - img->srcpad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC); - gst_element_add_pad (GST_ELEMENT (img), img->srcpad); - - img->elements_created = FALSE; -} - -static void -gst_camerabin_image_dispose (GstCameraBinImage * img) -{ - g_string_free (img->filename, TRUE); - img->filename = NULL; - - if (img->user_enc) { - gst_object_unref (img->user_enc); - img->user_enc = NULL; - } - - if (img->post) { - gst_object_unref (img->post); - img->post = NULL; - } - - G_OBJECT_CLASS (parent_class)->dispose ((GObject *) img); -} - -static GstStateChangeReturn -gst_camerabin_image_change_state (GstElement * element, - GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstCameraBinImage *img = GST_CAMERABIN_IMAGE (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!gst_camerabin_image_create_elements (img)) { - return GST_STATE_CHANGE_FAILURE; - } - /* Allow setting filename when image bin in READY state */ - gst_element_set_locked_state (img->sink, TRUE); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_element_set_locked_state (img->sink, FALSE); - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - /* Set sink to NULL in order to write the file _now_ */ - GST_INFO ("write img file: %s", img->filename->str); - gst_element_set_locked_state (img->sink, TRUE); - gst_element_set_state (img->sink, GST_STATE_NULL); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - gst_camerabin_image_destroy_elements (img); - break; - default: - break; - } - - return ret; -} - -gboolean -gst_camerabin_image_send_event (GstElement * element, GstEvent * event) -{ - GstCameraBinImage *bin = GST_CAMERABIN_IMAGE (element); - gboolean ret = FALSE; - - GST_INFO ("got %s event", GST_EVENT_TYPE_NAME (event)); - - if (GST_EVENT_IS_DOWNSTREAM (event)) { - ret = gst_pad_send_event (bin->sinkpad, event); - } else { - if (bin->sink) { - ret = gst_element_send_event (bin->sink, event); - } else { - GST_WARNING ("upstream event handling failed"); - } - } - - return ret; -} - -static void -gst_camerabin_image_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstCameraBinImage *bin = GST_CAMERABIN_IMAGE (object); - - switch (prop_id) { - case PROP_FILENAME: - g_string_assign (bin->filename, g_value_get_string (value)); - if (bin->sink) { - g_object_set (G_OBJECT (bin->sink), "location", bin->filename->str, - NULL); - } else { - GST_INFO ("no sink, not setting name yet"); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_camerabin_image_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstCameraBinImage *bin = GST_CAMERABIN_IMAGE (object); - - switch (prop_id) { - case PROP_FILENAME: - g_value_set_string (value, bin->filename->str); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* - * static helper functions implementation - */ - -/** - * metadata_write_probe: - * @pad: sink pad of metadata muxer - * @buffer: received buffer - * @u_data: image bin object - * - * Buffer probe that sets Xmp.dc.type and Xmp.dc.format tags - * to metadata muxer based on preceding element src pad caps. - * - * Returns: TRUE always - */ -static gboolean -metadata_write_probe (GstPad * pad, GstBuffer * buffer, gpointer u_data) -{ - /* Add XMP tags */ - GstCameraBinImage *img = NULL; - GstTagSetter *setter = NULL; - GstPad *srcpad = NULL; - GstCaps *caps = NULL; - GstStructure *st = NULL; - - img = GST_CAMERABIN_IMAGE (u_data); - - g_return_val_if_fail (img != NULL, TRUE); - - setter = GST_TAG_SETTER (img->meta_mux); - - if (!setter) { - GST_WARNING_OBJECT (img, "setting tags failed"); - goto done; - } - - /* Xmp.dc.type tag */ - gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE, - GST_TAG_CODEC, "Image", NULL); - /* Xmp.dc.format tag */ - if (img->enc) { - srcpad = gst_element_get_static_pad (img->enc, "src"); - } - GST_LOG_OBJECT (img, "srcpad:%" GST_PTR_FORMAT, srcpad); - if (srcpad) { - caps = gst_pad_get_negotiated_caps (srcpad); - GST_LOG_OBJECT (img, "caps:%" GST_PTR_FORMAT, caps); - if (caps) { - /* If there are many structures, we can't know which one to use */ - if (gst_caps_get_size (caps) != 1) { - GST_WARNING_OBJECT (img, "can't decide structure for format tag"); - goto done; - } - st = gst_caps_get_structure (caps, 0); - if (st) { - GST_DEBUG_OBJECT (img, "Xmp.dc.format:%s", gst_structure_get_name (st)); - gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE, - GST_TAG_VIDEO_CODEC, gst_structure_get_name (st), NULL); - } - } - } -done: - if (caps) - gst_caps_unref (caps); - if (srcpad) - gst_object_unref (srcpad); - - return TRUE; -} - - -/** - * gst_camerabin_image_create_elements: - * @img: a pointer to #GstCameraBinImage object - * - * This function creates needed #GstElements and resources to capture images. - * Use gst_camerabin_image_destroy_elements to release these resources. - * - * Image bin: - * img->sinkpad ! [ post process !] tee name=t0 ! encoder ! metadata ! filesink - * t0. ! queue ! img->srcpad - * - * Returns: %TRUE if succeeded or FALSE if failed - */ -static gboolean -gst_camerabin_image_create_elements (GstCameraBinImage * img) -{ - GstPad *sinkpad = NULL, *img_sinkpad = NULL, *img_srcpad = NULL; - gboolean ret = FALSE; - GstBin *imgbin = NULL; - - g_return_val_if_fail (img != NULL, FALSE); - - GST_DEBUG ("creating image capture elements"); - - imgbin = GST_BIN (img); - - if (img->elements_created) { - GST_WARNING ("elements already created"); - ret = TRUE; - goto done; - } else { - img->elements_created = TRUE; - } - - /* Create image pre/post-processing element if any */ - if (img->post) { - if (!gst_camerabin_add_element (imgbin, img->post)) { - goto done; - } - img_sinkpad = gst_element_get_static_pad (img->post, "sink"); - } - - /* Create tee */ - if (!(img->tee = gst_camerabin_create_and_add_element (imgbin, "tee"))) { - goto done; - } - - /* Set up sink ghost pad for img bin */ - if (!img_sinkpad) { - img_sinkpad = gst_element_get_static_pad (img->tee, "sink"); - } - gst_ghost_pad_set_target (GST_GHOST_PAD (img->sinkpad), img_sinkpad); - - /* Add colorspace converter */ - img->pad_tee_enc = gst_element_get_request_pad (img->tee, "src%d"); - if (!gst_camerabin_create_and_add_element (imgbin, "ffmpegcolorspace")) { - goto done; - } - - /* Create image encoder */ - if (img->user_enc) { - img->enc = img->user_enc; - if (!gst_camerabin_add_element (imgbin, img->enc)) { - goto done; - } - } else if (!(img->enc = - gst_camerabin_create_and_add_element (imgbin, DEFAULT_ENC))) { - goto done; - } - - /* Create metadata element */ - if (!(img->meta_mux = - gst_camerabin_create_and_add_element (imgbin, DEFAULT_META_MUX))) { - goto done; - } - /* Add probe for XMP metadata writing */ - sinkpad = gst_element_get_static_pad (img->meta_mux, "sink"); - gst_pad_add_buffer_probe (sinkpad, G_CALLBACK (metadata_write_probe), img); - gst_object_unref (sinkpad); - /* Set "Intel" exif byte-order if possible */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS (img->meta_mux), - "exif-byte-order")) { - g_object_set (G_OBJECT (img->meta_mux), "exif-byte-order", 1, NULL); - } - - /* Create file sink element */ - if (!(img->sink = - gst_camerabin_create_and_add_element (imgbin, DEFAULT_SINK))) { - goto done; - } - - /* Create queue element leading to view finder, attaches it to the tee */ - img->pad_tee_view = gst_element_get_request_pad (img->tee, "src%d"); - if (!(img->queue = gst_camerabin_create_and_add_element (imgbin, "queue"))) { - goto done; - } - - /* Set properties */ - g_object_set (G_OBJECT (img->sink), "location", img->filename->str, NULL); - g_object_set (G_OBJECT (img->sink), "async", FALSE, NULL); - - g_object_set (G_OBJECT (img->queue), "max-size-buffers", 1, "leaky", 2, NULL); - - /* Set up src ghost pad for img bin */ - img_srcpad = gst_element_get_static_pad (img->queue, "src"); - gst_ghost_pad_set_target (GST_GHOST_PAD (img->srcpad), img_srcpad); - - /* Never let image bin eos events reach view finder */ - gst_pad_add_event_probe (img->srcpad, - G_CALLBACK (gst_camerabin_drop_eos_probe), img); - - ret = TRUE; - -done: - - if (img_srcpad) { - gst_object_unref (img_srcpad); - } - if (img_sinkpad) { - gst_object_unref (img_sinkpad); - } - if (!ret) { - gst_camerabin_image_destroy_elements (img); - } - - return ret; -} - - -/** - * gst_camerabin_image_destroy_elements: - * @img: a pointer to #GstCameraBinImage object - * - * This function releases resources allocated in - * gst_camerabin_image_create_elements. - * - */ -static void -gst_camerabin_image_destroy_elements (GstCameraBinImage * img) -{ - GST_LOG ("destroying img elements"); - if (img->pad_tee_enc) { - gst_element_release_request_pad (img->tee, img->pad_tee_enc); - img->pad_tee_enc = NULL; - } - - if (img->pad_tee_view) { - gst_element_release_request_pad (img->tee, img->pad_tee_view); - img->pad_tee_view = NULL; - } - - gst_ghost_pad_set_target (GST_GHOST_PAD (img->sinkpad), NULL); - gst_ghost_pad_set_target (GST_GHOST_PAD (img->srcpad), NULL); - - gst_camerabin_remove_elements_from_bin (GST_BIN (img)); - - img->post = NULL; - img->tee = NULL; - img->enc = NULL; - img->meta_mux = NULL; - img->sink = NULL; - img->queue = NULL; - - img->elements_created = FALSE; -} - -void -gst_camerabin_image_set_encoder (GstCameraBinImage * img, GstElement * encoder) -{ - if (img->user_enc) - gst_object_unref (img->user_enc); - if (encoder) - gst_object_ref (encoder); - - img->user_enc = encoder; -} - -void -gst_camerabin_image_set_postproc (GstCameraBinImage * img, - GstElement * postproc) -{ - if (img->post) - gst_object_unref (img->post); - if (postproc) - gst_object_ref (postproc); - - img->post = postproc; -} - -GstElement * -gst_camerabin_image_get_encoder (GstCameraBinImage * img) -{ - GstElement *enc; - - if (img->user_enc) { - enc = img->user_enc; - } else { - enc = img->enc; - } - - return enc; -} - -GstElement * -gst_camerabin_image_get_postproc (GstCameraBinImage * img) -{ - return img->post; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/camerabinimage.h --- a/gst_plugins_good/gst/camerabin/camerabinimage.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -#ifndef __CAMERABIN_IMAGE_H__ -#define __CAMERABIN_IMAGE_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_CAMERABIN_IMAGE (gst_camerabin_image_get_type()) -#define GST_CAMERABIN_IMAGE_CAST(obj) ((GstCameraBinImage*)(obj)) -#define GST_CAMERABIN_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAMERABIN_IMAGE,GstCameraBinImage)) -#define GST_CAMERABIN_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAMERABIN_IMAGE,GstCameraBinImageClass)) -#define GST_IS_CAMERABIN_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAMERABIN_IMAGE)) -#define GST_IS_CAMERABIN_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAMERABIN_IMAGE)) - -/** - * GstCameraBinImage: - * - * The opaque #GstCameraBinImage structure. - */ - -typedef struct _GstCameraBinImage GstCameraBinImage; -typedef struct _GstCameraBinImageClass GstCameraBinImageClass; - -struct _GstCameraBinImage -{ - GstBin parent; - GString *filename; - - /* Ghost pads of image bin */ - GstPad *sinkpad; - GstPad *srcpad; - - /* Tee src pad leading to image encoder */ - GstPad *pad_tee_enc; - /* Tee src pad leading to view finder */ - GstPad *pad_tee_view; - - GstElement *post; - - GstElement *tee; - GstElement *enc; - GstElement *user_enc; - GstElement *meta_mux; - GstElement *sink; - GstElement *queue; - - gboolean elements_created; -}; - -struct _GstCameraBinImageClass -{ - GstBinClass parent_class; -}; - -#ifdef __SYMBIAN32__ -IMPORT_C -#endif -GType gst_camerabin_image_get_type (void); - -void -gst_camerabin_image_set_encoder (GstCameraBinImage * img, GstElement * encoder); - -void -gst_camerabin_image_set_postproc (GstCameraBinImage * img, - GstElement * postproc); - -GstElement *gst_camerabin_image_get_encoder (GstCameraBinImage * img); - -GstElement *gst_camerabin_image_get_postproc (GstCameraBinImage * img); - -G_END_DECLS - -#endif /* #ifndef __CAMERABIN_IMAGE_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/camerabinvideo.c --- a/gst_plugins_good/gst/camerabin/camerabinvideo.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,829 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -/** - * SECTION:camerabinvideo - * @short_description: video recording module of #GstCameraBin - * - * - * - * - * The pipeline for this module is: - * - * - * - *----------------------------------------------------------------------------- - * audiosrc -> audio_queue -> audioconvert -> volume -> audioenc - * > videomux -> filesink - * video_queue -> [timeoverlay] -> videoenc - * -> [post proc] -> tee < - * queue -> - *----------------------------------------------------------------------------- - * - * - * - * The properties of elements are: - * - * queue - "leaky", 2 (Leaky on downstream (old buffers)) - * - * - * - */ - -/* - * includes - */ - - -#include -#include "camerabingeneral.h" - -#include "camerabinvideo.h" - -#ifdef __SYMBIAN32__ -#include -#endif -/* - * defines and static global vars - */ - -/* internal element names */ - -#define DEFAULT_AUD_SRC "pulsesrc" -#define DEFAULT_AUD_ENC "vorbisenc" -#define DEFAULT_VID_ENC "theoraenc" -#define DEFAULT_MUX "oggmux" -#define DEFAULT_SINK "filesink" - -#define USE_AUDIO_CONVERSION 1 - -enum -{ - PROP_0, - PROP_FILENAME -}; - -static void gst_camerabin_video_dispose (GstCameraBinVideo * sink); -static void gst_camerabin_video_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_camerabin_video_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static GstClock *gst_camerabin_video_provide_clock (GstElement * elem); -static GstStateChangeReturn -gst_camerabin_video_change_state (GstElement * element, - GstStateChange transition); - -static - gboolean camerabin_video_pad_tee_src0_have_buffer (GstPad * pad, - GstBuffer * buffer, gpointer u_data); -static gboolean camerabin_video_pad_aud_src_have_buffer (GstPad * pad, - GstBuffer * buffer, gpointer u_data); -static gboolean camerabin_video_sink_have_event (GstPad * pad, GstEvent * event, - gpointer u_data); -static gboolean gst_camerabin_video_create_elements (GstCameraBinVideo * vid); -static void gst_camerabin_video_destroy_elements (GstCameraBinVideo * vid); - -GST_BOILERPLATE (GstCameraBinVideo, gst_camerabin_video, GstBin, GST_TYPE_BIN); - -static const GstElementDetails gst_camerabin_video_details = -GST_ELEMENT_DETAILS ("Video capture bin for camerabin", - "Bin/Video", - "Process and store video data", - "Edgard Lima \n" - "Nokia Corporation "); - -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - - -/* GObject methods implementation */ - -static void -gst_camerabin_video_base_init (gpointer klass) -{ - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (eklass, - gst_static_pad_template_get (&sink_template)); - gst_element_class_add_pad_template (eklass, - gst_static_pad_template_get (&src_template)); - gst_element_class_set_details (eklass, &gst_camerabin_video_details); -} - -static void -gst_camerabin_video_class_init (GstCameraBinVideoClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - - gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = - (GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_camerabin_video_dispose); - eklass->change_state = GST_DEBUG_FUNCPTR (gst_camerabin_video_change_state); - - eklass->provide_clock = GST_DEBUG_FUNCPTR (gst_camerabin_video_provide_clock); - - gobject_class->set_property = - GST_DEBUG_FUNCPTR (gst_camerabin_video_set_property); - gobject_class->get_property = - GST_DEBUG_FUNCPTR (gst_camerabin_video_get_property); - - /** - * GstCameraBinVideo:filename: - * - * This property can be used to specify the filename of the video. - * - **/ - g_object_class_install_property (gobject_class, PROP_FILENAME, - g_param_spec_string ("filename", "Filename", - "Filename of the video to save", NULL, G_PARAM_READWRITE)); -} - -static void -gst_camerabin_video_init (GstCameraBinVideo * vid, - GstCameraBinVideoClass * g_class) -{ - vid->filename = g_string_new (""); - - vid->user_post = NULL; - vid->user_vid_enc = NULL; - vid->user_aud_enc = NULL; - vid->user_aud_src = NULL; - vid->user_mux = NULL; - - vid->aud_src = NULL; - vid->sink = NULL; - vid->tee = NULL; - vid->volume = NULL; - vid->video_queue = NULL; - - vid->tee_video_srcpad = NULL; - vid->tee_vf_srcpad = NULL; - - vid->pending_eos = NULL; - - /* Create src and sink ghost pads */ - vid->sinkpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK); - gst_element_add_pad (GST_ELEMENT (vid), vid->sinkpad); - - vid->srcpad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC); - gst_element_add_pad (GST_ELEMENT (vid), vid->srcpad); - - /* Add probe for handling eos when stopping recording */ - gst_pad_add_event_probe (vid->sinkpad, - G_CALLBACK (camerabin_video_sink_have_event), vid); -} - -static void -gst_camerabin_video_dispose (GstCameraBinVideo * vid) -{ - GST_DEBUG_OBJECT (vid, "disposing"); - - g_string_free (vid->filename, TRUE); - vid->filename = NULL; - - if (vid->user_post) { - gst_object_unref (vid->user_post); - vid->user_post = NULL; - } - - if (vid->user_vid_enc) { - gst_object_unref (vid->user_vid_enc); - vid->user_vid_enc = NULL; - } - - if (vid->user_aud_enc) { - gst_object_unref (vid->user_aud_enc); - vid->user_aud_enc = NULL; - } - - if (vid->user_aud_src) { - gst_object_unref (vid->user_aud_src); - vid->user_aud_src = NULL; - } - - if (vid->user_mux) { - gst_object_unref (vid->user_mux); - vid->user_mux = NULL; - } - - G_OBJECT_CLASS (parent_class)->dispose ((GObject *) vid); -} - - -static void -gst_camerabin_video_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstCameraBinVideo *bin = GST_CAMERABIN_VIDEO (object); - - switch (prop_id) { - case PROP_FILENAME: - g_string_assign (bin->filename, g_value_get_string (value)); - if (bin->sink) { - g_object_set (G_OBJECT (bin->sink), "location", bin->filename->str, - NULL); - } else { - GST_INFO ("no sink, not setting name yet"); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_camerabin_video_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstCameraBinVideo *bin = GST_CAMERABIN_VIDEO (object); - - switch (prop_id) { - case PROP_FILENAME: - g_value_set_string (value, bin->filename->str); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* GstElement methods implementation */ - -static GstClock * -gst_camerabin_video_provide_clock (GstElement * elem) -{ - GstElement *aud_src = GST_CAMERABIN_VIDEO (elem)->aud_src; - if (aud_src) { - return gst_element_provide_clock (aud_src); - } else { - return NULL; - } -} - -static GstStateChangeReturn -gst_camerabin_video_change_state (GstElement * element, - GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstCameraBinVideo *vid = GST_CAMERABIN_VIDEO (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!gst_camerabin_video_create_elements (vid)) { - return GST_STATE_CHANGE_FAILURE; - } - /* Don't change sink to READY yet to allow changing the - filename in READY state. */ - gst_element_set_locked_state (vid->sink, TRUE); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - vid->calculate_adjust_ts_video = TRUE; - vid->calculate_adjust_ts_aud = TRUE; - g_object_set (G_OBJECT (vid->sink), "async", FALSE, NULL); - gst_element_set_locked_state (vid->sink, FALSE); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - vid->calculate_adjust_ts_video = TRUE; - vid->calculate_adjust_ts_aud = TRUE; - break; - - case GST_STATE_CHANGE_PAUSED_TO_READY: - /* Set sink to NULL in order to write the file _now_ */ - GST_INFO ("write vid file: %s", vid->filename->str); - gst_element_set_locked_state (vid->sink, TRUE); - gst_element_set_state (vid->sink, GST_STATE_NULL); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - if (vid->pending_eos) { - /* Video bin is still paused, so push eos directly to video queue */ - GST_DEBUG_OBJECT (vid, "pushing pending eos"); - gst_pad_push_event (vid->tee_video_srcpad, vid->pending_eos); - vid->pending_eos = NULL; - } - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - /* Reset counters related to timestamp rewriting */ - vid->adjust_ts_video = 0; - vid->last_ts_video = 0; - vid->adjust_ts_aud = 0; - vid->last_ts_aud = 0; - - if (vid->pending_eos) { - gst_event_unref (vid->pending_eos); - vid->pending_eos = NULL; - } - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_camerabin_video_destroy_elements (vid); - break; - default: - break; - } - - return ret; -} - -/* - * static helper functions implementation - */ - -/** - * camerabin_video_pad_tee_src0_have_buffer: - * @pad: tee src pad leading to video encoding - * @event: received buffer - * @u_data: video bin object - * - * Buffer probe for rewriting video buffer timestamps. - * - * Returns: TRUE always - */ -static gboolean -camerabin_video_pad_tee_src0_have_buffer (GstPad * pad, GstBuffer * buffer, - gpointer u_data) -{ - GstCameraBinVideo *vid = (GstCameraBinVideo *) u_data; - - GST_LOG ("buffer in with size %d ts %" GST_TIME_FORMAT, - GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); - - if (G_UNLIKELY (vid->calculate_adjust_ts_video)) { - GstEvent *event; - GstObject *tee; - GstPad *sinkpad; - vid->adjust_ts_video = GST_BUFFER_TIMESTAMP (buffer) - vid->last_ts_video; - vid->calculate_adjust_ts_video = FALSE; - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, - 0, GST_CLOCK_TIME_NONE, vid->last_ts_video); - /* Send the newsegment to both view finder and video bin */ - tee = gst_pad_get_parent (pad); - sinkpad = gst_element_get_static_pad (GST_ELEMENT (tee), "sink"); - gst_pad_send_event (sinkpad, event); - gst_object_unref (tee); - gst_object_unref (sinkpad); - GST_LOG_OBJECT (vid, "vid ts adjustment: %" GST_TIME_FORMAT, - GST_TIME_ARGS (vid->adjust_ts_video)); - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); - } - GST_BUFFER_TIMESTAMP (buffer) -= vid->adjust_ts_video; - vid->last_ts_video = GST_BUFFER_TIMESTAMP (buffer); - if (GST_BUFFER_DURATION_IS_VALID (buffer)) - vid->last_ts_video += GST_BUFFER_DURATION (buffer); - - - GST_LOG ("buffer out with size %d ts %" GST_TIME_FORMAT, - GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); - return TRUE; -} - -/** - * camerabin_video_pad_aud_src_have_buffer: - * @pad: audio source src pad - * @event: received buffer - * @u_data: video bin object - * - * Buffer probe for rewriting audio buffer timestamps. - * - * Returns: TRUE always - */ -static gboolean -camerabin_video_pad_aud_src_have_buffer (GstPad * pad, GstBuffer * buffer, - gpointer u_data) -{ - GstCameraBinVideo *vid = (GstCameraBinVideo *) u_data; - - if (vid->calculate_adjust_ts_aud) { - GstEvent *event; - GstPad *peerpad = NULL; - vid->adjust_ts_aud = GST_BUFFER_TIMESTAMP (buffer) - vid->last_ts_aud; - vid->calculate_adjust_ts_aud = FALSE; - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, - 0, GST_CLOCK_TIME_NONE, vid->last_ts_aud); - peerpad = gst_pad_get_peer (pad); - if (peerpad) { - gst_pad_send_event (peerpad, event); - gst_object_unref (peerpad); - } - GST_LOG_OBJECT (vid, "aud ts adjustment: %" GST_TIME_FORMAT, - GST_TIME_ARGS (vid->adjust_ts_aud)); - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); - } - GST_BUFFER_TIMESTAMP (buffer) -= vid->adjust_ts_aud; - vid->last_ts_aud = GST_BUFFER_TIMESTAMP (buffer); - if (GST_BUFFER_DURATION_IS_VALID (buffer)) - vid->last_ts_aud += GST_BUFFER_DURATION (buffer); - GST_LOG ("buffer out with size %d ts %" GST_TIME_FORMAT, - GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); - return TRUE; -} - -/** - * camerabin_video_sink_have_event: - * @pad: video bin sink pad - * @event: received event - * @u_data: video bin object - * - * Event probe for video bin eos handling. - * Copies the eos event to audio branch of video bin. - * - * Returns: FALSE to drop the event, TRUE otherwise - */ -static gboolean -camerabin_video_sink_have_event (GstPad * pad, GstEvent * event, - gpointer u_data) -{ - GstCameraBinVideo *vid = (GstCameraBinVideo *) u_data; - gboolean ret = TRUE; - - GST_DEBUG_OBJECT (vid, "got videobin sink event: %s", - GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - if (vid->aud_src) { - GST_DEBUG_OBJECT (vid, "copying %s to audio branch", - GST_EVENT_TYPE_NAME (event)); - gst_element_send_event (vid->aud_src, gst_event_copy (event)); - } - - /* If we're paused, we can't pass eos to video now to avoid blocking. - Instead send eos when changing to playing next time. */ - if (GST_STATE (GST_ELEMENT (vid)) == GST_STATE_PAUSED) { - GST_DEBUG_OBJECT (vid, "paused, delay eos sending"); - vid->pending_eos = gst_event_ref (event); - ret = FALSE; /* Drop the event */ - } - break; - default: - break; - } - return ret; -} - -/** - * gst_camerabin_video_create_elements: - * @vid: a pointer to #GstCameraBinVideo - * - * This function creates the needed #GstElements and resources to record videos. - * Use gst_camerabin_video_destroy_elements() to free these resources. - * - * Returns: %TRUE if succeeded or FALSE if failed - */ -static gboolean -gst_camerabin_video_create_elements (GstCameraBinVideo * vid) -{ - GstPad *pad = NULL, *vid_sinkpad = NULL, *vid_srcpad = NULL; - GstBin *vidbin = GST_BIN (vid); - GstElement *queue = NULL; - - vid->adjust_ts_video = 0; - vid->last_ts_video = 0; - vid->calculate_adjust_ts_video = FALSE; - - vid->adjust_ts_aud = 0; - vid->last_ts_aud = 0; - vid->calculate_adjust_ts_aud = FALSE; - - /* Add video post processing element if any */ - if (vid->user_post) { - if (!gst_camerabin_add_element (vidbin, vid->user_post)) { - goto error; - } - vid_sinkpad = gst_element_get_static_pad (vid->user_post, "sink"); - } - - /* Add tee element */ - if (!(vid->tee = gst_camerabin_create_and_add_element (vidbin, "tee"))) { - goto error; - } - - /* Set up sink ghost pad for video bin */ - if (!vid_sinkpad) { - vid_sinkpad = gst_element_get_static_pad (vid->tee, "sink"); - } - gst_ghost_pad_set_target (GST_GHOST_PAD (vid->sinkpad), vid_sinkpad); - - - /* Add queue element for video */ - vid->tee_video_srcpad = gst_element_get_request_pad (vid->tee, "src%d"); - if (!(vid->video_queue = - gst_camerabin_create_and_add_element (vidbin, "queue"))) { - goto error; - } - - /* Add probe for rewriting video timestamps */ - gst_pad_add_buffer_probe (vid->tee_video_srcpad, - G_CALLBACK (camerabin_video_pad_tee_src0_have_buffer), vid); - - -#ifdef USE_TIMEOVERLAY - /* Add timeoverlay element to visualize elapsed time for debugging */ - if (!(gst_camerabin_create_and_add_element (vidbin, "timeoverlay"))) { - goto error; - } -#endif - - /* Add user set or default video encoder element */ - if (vid->user_vid_enc) { - vid->vid_enc = vid->user_vid_enc; - if (!gst_camerabin_add_element (vidbin, vid->vid_enc)) { - goto error; - } - } else if (!(vid->vid_enc = - gst_camerabin_create_and_add_element (vidbin, DEFAULT_VID_ENC))) { - goto error; - } - - /* Add user set or default muxer element */ - if (vid->user_mux) { - vid->muxer = vid->user_mux; - if (!gst_camerabin_add_element (vidbin, vid->muxer)) { - goto error; - } - } else if (!(vid->muxer = - gst_camerabin_create_and_add_element (vidbin, DEFAULT_MUX))) { - goto error; - } - - /* Add sink element for storing the video */ - if (!(vid->sink = - gst_camerabin_create_and_add_element (vidbin, DEFAULT_SINK))) { - goto error; - } - g_object_set (G_OBJECT (vid->sink), "location", vid->filename->str, NULL); - - - /* Add user set or default audio source element */ - if (vid->user_aud_src) { - vid->aud_src = vid->user_aud_src; - if (!gst_camerabin_add_element (vidbin, vid->aud_src)) { - goto error; - } - } else if (!(vid->aud_src = - gst_camerabin_create_and_add_element (vidbin, DEFAULT_AUD_SRC))) { - goto error; - } - - /* Add queue element for audio */ - if (!(queue = gst_camerabin_create_and_add_element (vidbin, "queue"))) { - goto error; - } - queue = NULL; - - /* Add optional audio conversion and volume elements and - raise no errors if adding them fails */ -#ifdef USE_AUDIO_CONVERSION - if (!gst_camerabin_try_add_element (vidbin, - gst_element_factory_make ("audioconvert", NULL))) { - GST_WARNING_OBJECT (vid, "unable to add audio conversion element"); - /* gst_camerabin_try_add_element() destroyed the element */ - } -#endif - vid->volume = gst_element_factory_make ("volume", NULL); - if (!gst_camerabin_try_add_element (vidbin, vid->volume)) { - GST_WARNING_OBJECT (vid, "unable to add volume element"); - /* gst_camerabin_try_add_element() destroyed the element */ - vid->volume = NULL; - } - - /* Add user set or default audio encoder element */ - if (vid->user_aud_enc) { - vid->aud_enc = vid->user_aud_enc; - if (!gst_camerabin_add_element (vidbin, vid->aud_enc)) { - goto error; - } - } else if (!(vid->aud_enc = - gst_camerabin_create_and_add_element (vidbin, DEFAULT_AUD_ENC))) { - goto error; - } - - /* Link audio part to the muxer */ - if (!gst_element_link (vid->aud_enc, vid->muxer)) { - GST_ELEMENT_ERROR (vid, CORE, NEGOTIATION, (NULL), - ("linking audio encoder and muxer failed")); - goto error; - } - - /* Add queue leading out of the video bin and to view finder */ - vid->tee_vf_srcpad = gst_element_get_request_pad (vid->tee, "src%d"); - if (!(queue = gst_camerabin_create_and_add_element (vidbin, "queue"))) { - goto error; - } - /* Set queue leaky, we don't want to block video encoder feed, but - prefer leaking view finder buffers instead. */ - g_object_set (G_OBJECT (queue), "leaky", 2, NULL); - - /* Set up src ghost pad for video bin */ - vid_srcpad = gst_element_get_static_pad (queue, "src"); - gst_ghost_pad_set_target (GST_GHOST_PAD (vid->srcpad), vid_srcpad); - /* Never let video bin eos events reach view finder */ - gst_pad_add_event_probe (vid_srcpad, - G_CALLBACK (gst_camerabin_drop_eos_probe), vid); - - pad = gst_element_get_static_pad (vid->aud_src, "src"); - gst_pad_add_buffer_probe (pad, - G_CALLBACK (camerabin_video_pad_aud_src_have_buffer), vid); - gst_object_unref (pad); - - GST_DEBUG ("created video elements"); - - return TRUE; - -error: - - gst_camerabin_video_destroy_elements (vid); - - return FALSE; - -} - -/** - * gst_camerabin_video_destroy_elements: - * @vid: a pointer to #GstCameraBinVideo - * - * This function destroys all the elements created by - * gst_camerabin_video_create_elements(). - * - */ -static void -gst_camerabin_video_destroy_elements (GstCameraBinVideo * vid) -{ - GST_DEBUG ("destroying video elements"); - - /* Release tee request pads */ - if (vid->tee_video_srcpad) { - gst_element_release_request_pad (vid->tee, vid->tee_video_srcpad); - vid->tee_video_srcpad = NULL; - } - if (vid->tee_vf_srcpad) { - gst_element_release_request_pad (vid->tee, vid->tee_vf_srcpad); - vid->tee_vf_srcpad = NULL; - } - - gst_ghost_pad_set_target (GST_GHOST_PAD (vid->sinkpad), NULL); - gst_ghost_pad_set_target (GST_GHOST_PAD (vid->srcpad), NULL); - - gst_camerabin_remove_elements_from_bin (GST_BIN (vid)); - - vid->aud_src = NULL; - vid->sink = NULL; - vid->tee = NULL; - vid->volume = NULL; - vid->video_queue = NULL; - vid->vid_enc = NULL; - vid->aud_enc = NULL; - vid->muxer = NULL; - - if (vid->pending_eos) { - gst_event_unref (vid->pending_eos); - vid->pending_eos = NULL; - } - - return; -} - -/* - * Set & get mute and video capture elements - */ - -void -gst_camerabin_video_set_mute (GstCameraBinVideo * vid, gboolean mute) -{ - if (vid && vid->volume) { - GST_DEBUG_OBJECT (vid, "setting mute %s", mute ? "on" : "off"); - g_object_set (vid->volume, "mute", mute, NULL); - } -} - -void -gst_camerabin_video_set_post (GstCameraBinVideo * vid, GstElement * post) -{ - GstElement **user_post; - GST_DEBUG_OBJECT (vid, "setting video post processing: %" GST_PTR_FORMAT, - post); - GST_OBJECT_LOCK (vid); - user_post = &vid->user_post; - gst_object_replace ((GstObject **) user_post, GST_OBJECT (post)); - GST_OBJECT_UNLOCK (vid); -} - -void -gst_camerabin_video_set_video_enc (GstCameraBinVideo * vid, - GstElement * video_enc) -{ - GstElement **user_vid_enc; - GST_DEBUG_OBJECT (vid, "setting video encoder: %" GST_PTR_FORMAT, video_enc); - GST_OBJECT_LOCK (vid); - user_vid_enc = &vid->user_vid_enc; - gst_object_replace ((GstObject **) user_vid_enc, GST_OBJECT (video_enc)); - GST_OBJECT_UNLOCK (vid); -} - -void -gst_camerabin_video_set_audio_enc (GstCameraBinVideo * vid, - GstElement * audio_enc) -{ - GstElement **user_aud_enc; - GST_DEBUG_OBJECT (vid, "setting audio encoder: %" GST_PTR_FORMAT, audio_enc); - GST_OBJECT_LOCK (vid); - user_aud_enc = &vid->user_aud_enc; - gst_object_replace ((GstObject **) user_aud_enc, GST_OBJECT (audio_enc)); - GST_OBJECT_UNLOCK (vid); -} - -void -gst_camerabin_video_set_muxer (GstCameraBinVideo * vid, GstElement * muxer) -{ - GstElement **user_mux; - GST_DEBUG_OBJECT (vid, "setting muxer: %" GST_PTR_FORMAT, muxer); - GST_OBJECT_LOCK (vid); - user_mux = &vid->user_mux; - gst_object_replace ((GstObject **) user_mux, GST_OBJECT (muxer)); - GST_OBJECT_UNLOCK (vid); -} - -void -gst_camerabin_video_set_audio_src (GstCameraBinVideo * vid, - GstElement * audio_src) -{ - GstElement **user_aud_src; - GST_DEBUG_OBJECT (vid, "setting audio source: %" GST_PTR_FORMAT, audio_src); - GST_OBJECT_LOCK (vid); - user_aud_src = &vid->user_aud_src; - gst_object_replace ((GstObject **) user_aud_src, GST_OBJECT (audio_src)); - GST_OBJECT_UNLOCK (vid); -} - -gboolean -gst_camerabin_video_get_mute (GstCameraBinVideo * vid) -{ - gboolean mute = ARG_DEFAULT_MUTE; - - if (vid && vid->volume) { - g_object_get (vid->volume, "mute", &mute, NULL); - } - return mute; -} - -GstElement * -gst_camerabin_video_get_post (GstCameraBinVideo * vid) -{ - return vid->user_post; -} - -GstElement * -gst_camerabin_video_get_video_enc (GstCameraBinVideo * vid) -{ - return vid->vid_enc ? vid->vid_enc : vid->user_vid_enc; -} - -GstElement * -gst_camerabin_video_get_audio_enc (GstCameraBinVideo * vid) -{ - return vid->aud_enc ? vid->aud_enc : vid->user_aud_enc; -} - -GstElement * -gst_camerabin_video_get_muxer (GstCameraBinVideo * vid) -{ - return vid->muxer ? vid->muxer : vid->user_mux; -} - -GstElement * -gst_camerabin_video_get_audio_src (GstCameraBinVideo * vid) -{ - return vid->aud_src ? vid->aud_src : vid->user_aud_src; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/camerabinvideo.h --- a/gst_plugins_good/gst/camerabin/camerabinvideo.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -#ifndef __CAMERABIN_VIDEO_H__ -#define __CAMERABIN_VIDEO_H__ - -#include - -G_BEGIN_DECLS - -//#define USE_TIMEOVERLAY 1 - -#define ARG_DEFAULT_MUTE FALSE - -#define GST_TYPE_CAMERABIN_VIDEO (gst_camerabin_video_get_type()) -#define GST_CAMERABIN_VIDEO_CAST(obj) ((GstCameraBinVideo*)(obj)) -#define GST_CAMERABIN_VIDEO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAMERABIN_VIDEO,GstCameraBinVideo)) -#define GST_CAMERABIN_VIDEO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAMERABIN_VIDEO,GstCameraBinVideoClass)) -#define GST_IS_CAMERABIN_VIDEO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAMERABIN_VIDEO)) -#define GST_IS_CAMERABIN_VIDEO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAMERABIN_VIDEO)) - -/** - * GstCameraBinVideo: - * - * The opaque #GstCameraBinVideo structure. - */ - -typedef struct _GstCameraBinVideo GstCameraBinVideo; -typedef struct _GstCameraBinVideoClass GstCameraBinVideoClass; - -struct _GstCameraBinVideo -{ - GstBin parent; - - GString *filename; - - /* A/V timestamp rewriting */ - guint64 adjust_ts_video; - guint64 last_ts_video; - gboolean calculate_adjust_ts_video; - - guint64 adjust_ts_aud; - guint64 last_ts_aud; - gboolean calculate_adjust_ts_aud; - - /* Sink and src pads of video bin */ - GstPad *sinkpad; - GstPad *srcpad; - - /* Tee src pads leading to video encoder and view finder */ - GstPad *tee_video_srcpad; - GstPad *tee_vf_srcpad; - - /* User set elements */ - GstElement *user_post; /* Video post processing */ - GstElement *user_vid_enc; - GstElement *user_aud_enc; - GstElement *user_aud_src; - GstElement *user_mux; - - /* Other elements */ - GstElement *aud_src; /* Audio source */ - GstElement *sink; /* Sink for recorded video */ - GstElement *tee; /* Split output to view finder and recording sink */ - GstElement *volume; /* Volume for muting */ - GstElement *video_queue; /* Buffer for raw video frames */ - GstElement *vid_enc; /* Video encoder */ - GstElement *aud_enc; /* Audio encoder */ - GstElement *muxer; /* Muxer */ - - GstEvent *pending_eos; -}; - -struct _GstCameraBinVideoClass -{ - GstBinClass parent_class; -}; - -#ifdef __SYMBIAN32__ -IMPORT_C -#endif -GType gst_camerabin_video_get_type (void); - -/* - * external function prototypes - */ - -void gst_camerabin_video_set_mute (GstCameraBinVideo * vid, gboolean mute); - -void gst_camerabin_video_set_post (GstCameraBinVideo * vid, GstElement * post); - -void -gst_camerabin_video_set_video_enc (GstCameraBinVideo * vid, - GstElement * video_enc); - -void -gst_camerabin_video_set_audio_enc (GstCameraBinVideo * vid, - GstElement * audio_enc); - -void -gst_camerabin_video_set_muxer (GstCameraBinVideo * vid, GstElement * muxer); - -void -gst_camerabin_video_set_audio_src (GstCameraBinVideo * vid, - GstElement * audio_src); - - -gboolean gst_camerabin_video_get_mute (GstCameraBinVideo * vid); - -GstElement *gst_camerabin_video_get_post (GstCameraBinVideo * vid); - -GstElement *gst_camerabin_video_get_video_enc (GstCameraBinVideo * vid); - -GstElement *gst_camerabin_video_get_audio_enc (GstCameraBinVideo * vid); - -GstElement *gst_camerabin_video_get_muxer (GstCameraBinVideo * vid); - -GstElement *gst_camerabin_video_get_audio_src (GstCameraBinVideo * vid); - -G_END_DECLS - -#endif /* #ifndef __CAMERABIN_VIDEO_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/gstcamerabin-marshal.c --- a/gst_plugins_good/gst/camerabin/gstcamerabin-marshal.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ - -#include - - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_char (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* VOID:INT,INT,INT,INT (gstcamerabin-marshal.list:4) */ -void -gst_camerabin_marshal_VOID__INT_INT_INT_INT (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__INT_INT_INT_INT) (gpointer data1, - gint arg_1, - gint arg_2, - gint arg_3, - gint arg_4, - gpointer data2); - register GMarshalFunc_VOID__INT_INT_INT_INT callback; - register GCClosure *cc = (GCClosure*) closure; - register gpointer data1, data2; - - g_return_if_fail (n_param_values == 5); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__INT_INT_INT_INT) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_int (param_values + 1), - g_marshal_value_peek_int (param_values + 2), - g_marshal_value_peek_int (param_values + 3), - g_marshal_value_peek_int (param_values + 4), - data2); -} - -/* VOID:INT,INT (gstcamerabin-marshal.list:5) */ -void -gst_camerabin_marshal_VOID__INT_INT (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__INT_INT) (gpointer data1, - gint arg_1, - gint arg_2, - gpointer data2); - register GMarshalFunc_VOID__INT_INT callback; - register GCClosure *cc = (GCClosure*) closure; - register gpointer data1, data2; - - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__INT_INT) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_int (param_values + 1), - g_marshal_value_peek_int (param_values + 2), - data2); -} - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/gstcamerabin-marshal.h --- a/gst_plugins_good/gst/camerabin/gstcamerabin-marshal.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ - -#ifndef __gst_camerabin_MARSHAL_H__ -#define __gst_camerabin_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -/* VOID:INT,INT,INT,INT (gstcamerabin-marshal.list:4) */ -extern void gst_camerabin_marshal_VOID__INT_INT_INT_INT (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); - -/* VOID:INT,INT (gstcamerabin-marshal.list:5) */ -extern void gst_camerabin_marshal_VOID__INT_INT (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); - -G_END_DECLS - -#endif /* __gst_camerabin_MARSHAL_H__ */ - diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/gstcamerabin.c --- a/gst_plugins_good/gst/camerabin/gstcamerabin.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2769 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -/** - * SECTION:gstcamerabin - * @short_description: camera capture bin - * - * - * - * GstCameraBin is a high-level camera object that encapsulates the gstreamer - * internals and provides a task based API for the application. It consists of - * three main data paths: view-finder, image capture and video capture. - * - * - * - * - * CameraBin structure - * Structural decomposition of CameraBin object. - * - * - * - * - * Example launch line - * - * - * gst-launch -v -m camerabin filename=test.jpeg - * - * - * - * - * Image capture - * - * Taking still images is initiated with the #GstCameraBin::user-start action - * signal. Once the image has captured, #GstCameraBin::img-done signal is fired. - * It allows to decide wheter to take another picture (burst capture, bracketing - * shot) or stop capturing. The last captured image is shown - * until one switches back to view finder using #GstCameraBin::user-stop action - * signal. - * - * - * Available resolutions can be taken from the #GstCameraBin:inputcaps property. - * Image capture resolution can be set with #GstCameraBin::user-image-res - * action signal. - * - * - * - * Video capture - * - * Video capture is started with the #GstCameraBin::user-start action signal too. - * In addition to image capture one can use #GstCameraBin::user-pause to - * pause recording and #GstCameraBin::user-stop to end recording. - * - * - * Available resolutions and fps can be taken from the #GstCameraBin:inputcaps - * property. #GstCameraBin::user-res-fps action signal can be used to set frame - * rate and resolution for the video recording and view finder as well. - * - * - * - * Photography interface - * - * GstCameraBin implements gst photography interface, which can be used to set - * and get different settings related to digital imaging. Since currently many - * of these settings require low-level support the photography interface support - * is dependent on video src element. In practice photography interface settings - * cannot be used successfully until in PAUSED state when the video src has - * opened the video device. - * - * - * - * States - * - * Elements within GstCameraBin are created and destroyed when switching - * between NULL and READY states. Therefore element properties should be set - * in NULL state. User set elements are not unreffed until GstCameraBin is - * unreffed or replaced by a new user set element. Initially only elements needed - * for view finder mode are created to speed up startup. Image bin and video bin - * elements are created when setting the mode or starting capture. - * - * - * - * - * - * Since the muxers tested so far have problems with discontinous buffers, QoS - * has been disabled, and then in order to record video, you MUST ensure that - * there is enough CPU to encode the video. Thus choose smart resolution and - * frames per second values. It is also highly recommended to avoid color - * conversions; make sure all the elements involved work with the same colorspace - * (i.e. rgb or yuv i420 or whatelse). - * - * - * - */ - -/* - * The pipeline in the camerabin is - * - * "image bin" - * videosrc ! crop ! scale ! out-sel <------> in-sel ! scale ! ffmpegcsp ! vfsink - * "video bin" - * - * it is possible to have 'ffmpegcolorspace' and 'capsfilter' just after - * v4l2camsrc - * - * The properties of elements are: - * - * vfsink - "sync", FALSE, "qos", FALSE - * output-selector - "resend-latest", FALSE - * input-selector - "select-all", TRUE - */ - -/* - * includes - */ - - -#ifdef HAVE_CONFIG_H -#include -#endif - - -#include -#include - -#include -/* FIXME: include #include and use _(" ") */ - -#ifndef __SYMBIAN32__ -#include -#else -#include -#endif - -#ifdef __SYMBIAN32__ -#include -#endif - - - - -#include "gstcamerabin.h" -#include "gstcamerabinxoverlay.h" -#include "gstcamerabincolorbalance.h" -#include "gstcamerabinphotography.h" - -#include "camerabingeneral.h" - -#include "gstcamerabin-marshal.h" - -#ifdef __SYMBIAN32__ -#include -#endif -/* - * enum and types - */ - -enum -{ - /* action signals */ - USER_START_SIGNAL, - USER_STOP_SIGNAL, - USER_PAUSE_SIGNAL, - USER_RES_FPS_SIGNAL, - USER_IMAGE_RES_SIGNAL, - /* emit signals */ - IMG_DONE_SIGNAL, - LAST_SIGNAL -}; - -enum -{ - ARG_0, - ARG_FILENAME, - ARG_MODE, - ARG_MUTE, - ARG_ZOOM, - ARG_IMAGE_POST, - ARG_IMAGE_ENC, - ARG_VIDEO_POST, - ARG_VIDEO_ENC, - ARG_AUDIO_ENC, - ARG_VIDEO_MUX, - ARG_VF_SINK, - ARG_VIDEO_SRC, - ARG_AUDIO_SRC, - ARG_INPUT_CAPS, - ARG_FILTER_CAPS -}; - -/* - * defines and static global vars - */ - -static guint camerabin_signals[LAST_SIGNAL]; - -#define GST_TYPE_CAMERABIN_MODE (gst_camerabin_mode_get_type ()) - -/* default and range values for args */ - -#define DEFAULT_MODE MODE_IMAGE -#define DEFAULT_ZOOM 100 -#define DEFAULT_WIDTH 640 -#define DEFAULT_HEIGHT 480 -#define DEFAULT_CAPTURE_WIDTH 800 -#define DEFAULT_CAPTURE_HEIGHT 600 -#define DEFAULT_FPS_N 0 /* makes it use the default */ -#define DEFAULT_FPS_D 1 -#define CAMERABIN_DEFAULT_VF_CAPS "video/x-raw-yuv,format=(fourcc)I420" -/* Using "bilinear" as default zoom method */ -#define CAMERABIN_DEFAULT_ZOOM_METHOD 1 - -#define MIN_ZOOM 100 -#define MAX_ZOOM 1000 -#define ZOOM_1X MIN_ZOOM - -#define DEFAULT_V4L2CAMSRC_DRIVER_NAME "omap3cam" - -/* internal element names */ - -#define USE_COLOR_CONVERTER 1 - -/* FIXME: Make sure this can work with autovideosrc and use that. */ -#define DEFAULT_SRC_VID_SRC "v4l2src" - -#define DEFAULT_VIEW_SINK "autovideosink" - -/* - * static helper functions declaration - */ - -static void camerabin_setup_src_elements (GstCameraBin * camera); - -static gboolean camerabin_create_src_elements (GstCameraBin * camera); - -static void camerabin_setup_view_elements (GstCameraBin * camera); - -static gboolean camerabin_create_view_elements (GstCameraBin * camera); - -static gboolean camerabin_create_elements (GstCameraBin * camera); - -static void camerabin_destroy_elements (GstCameraBin * camera); - -static void camerabin_dispose_elements (GstCameraBin * camera); - -static void gst_camerabin_change_mode (GstCameraBin * camera, gint mode); - -static void -gst_camerabin_change_filename (GstCameraBin * camera, const gchar * name); - -static void gst_camerabin_setup_zoom (GstCameraBin * camera); - -static GstCaps *gst_camerabin_get_allowed_input_caps (GstCameraBin * camera); - -static void gst_camerabin_rewrite_tags (GstCameraBin * camera); - -static void -gst_camerabin_set_capsfilter_caps (GstCameraBin * camera, GstCaps * new_caps); - -static void gst_camerabin_start_image_capture (GstCameraBin * camera); - -static void gst_camerabin_start_video_recording (GstCameraBin * camera); - -static gboolean -gst_camerabin_have_img_buffer (GstPad * pad, GstBuffer * buffer, - gpointer u_data); -static gboolean -gst_camerabin_have_vid_buffer (GstPad * pad, GstBuffer * buffer, - gpointer u_data); - -static void gst_camerabin_reset_to_view_finder (GstCameraBin * camera); - -static void gst_camerabin_do_stop (GstCameraBin * camera); - -static void -gst_camerabin_set_allowed_framerate (GstCameraBin * camera, - GstCaps * filter_caps); - -/* - * GObject callback functions declaration - */ - -static void gst_camerabin_base_init (gpointer gclass); - -static void gst_camerabin_class_init (GstCameraBinClass * klass); - -static void -gst_camerabin_init (GstCameraBin * camera, GstCameraBinClass * gclass); - -static void gst_camerabin_dispose (GObject * object); - -static void gst_camerabin_finalize (GObject * object); - -static void gst_camerabin_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); - -static void gst_camerabin_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static const GValue *gst_camerabin_find_better_framerate (GstCameraBin * camera, - GstStructure * st, const GValue * orig_framerate); -/* - * GstElement function declarations - */ - -static GstStateChangeReturn -gst_camerabin_change_state (GstElement * element, GstStateChange transition); - - -/* - * GstBin function declarations - */ -static void -gst_camerabin_handle_message_func (GstBin * bin, GstMessage * message); - - -/* - * Action signal function declarations - */ - -static void gst_camerabin_user_start (GstCameraBin * camera); - -static void gst_camerabin_user_stop (GstCameraBin * camera); - -static void gst_camerabin_user_pause (GstCameraBin * camera); - -static void -gst_camerabin_user_res_fps (GstCameraBin * camera, gint width, gint height, - gint fps_n, gint fps_d); - -static void -gst_camerabin_user_image_res (GstCameraBin * camera, gint width, gint height); - - -/* - * GST BOILERPLATE and GObject types - */ - -static GType -gst_camerabin_mode_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {MODE_IMAGE, "Still image capture (default)", "mode-image"}, - {MODE_VIDEO, "Video recording", "mode-video"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstCameraBinMode", values); - } - return gtype; -} - -static gboolean -gst_camerabin_iface_supported (GstImplementsInterface * iface, GType iface_type) -{ - GstCameraBin *camera = GST_CAMERABIN (iface); - - if (iface_type == GST_TYPE_X_OVERLAY) { - if (camera->view_sink) { - return GST_IS_X_OVERLAY (camera->view_sink); - } - } else if (iface_type == GST_TYPE_COLOR_BALANCE) { - if (camera->src_vid_src) { - return GST_IS_COLOR_BALANCE (camera->src_vid_src); - } - } else if (iface_type == GST_TYPE_TAG_SETTER) { - /* Note: Tag setter elements aren't - present when image and video bin in NULL */ - GstElement *setter; - setter = gst_bin_get_by_interface (GST_BIN (camera), iface_type); - if (setter) { - gst_object_unref (setter); - return TRUE; - } else { - return FALSE; - } - } else if (iface_type == GST_TYPE_PHOTOGRAPHY) { - if (camera->src_vid_src) { - return GST_IS_PHOTOGRAPHY (camera->src_vid_src); - } - } - - return FALSE; -} - -static void -gst_camerabin_interface_init (GstImplementsInterfaceClass * klass) -{ - /* - * default virtual functions - */ - klass->supported = gst_camerabin_iface_supported; -} - -static void -camerabin_init_interfaces (GType type) -{ - - static const GInterfaceInfo camerabin_info = { - (GInterfaceInitFunc) gst_camerabin_interface_init, - NULL, - NULL, - }; - - static const GInterfaceInfo camerabin_xoverlay_info = { - (GInterfaceInitFunc) gst_camerabin_xoverlay_init, - NULL, - NULL, - }; - - static const GInterfaceInfo camerabin_color_balance_info = { - (GInterfaceInitFunc) gst_camerabin_color_balance_init, - NULL, - NULL, - }; - - static const GInterfaceInfo camerabin_tagsetter_info = { - NULL, - NULL, - NULL, - }; - static const GInterfaceInfo camerabin_photography_info = { - (GInterfaceInitFunc) gst_camerabin_photography_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, - GST_TYPE_IMPLEMENTS_INTERFACE, &camerabin_info); - - g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, - &camerabin_xoverlay_info); - - g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE, - &camerabin_color_balance_info); - - g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, - &camerabin_tagsetter_info); - - g_type_add_interface_static (type, GST_TYPE_PHOTOGRAPHY, - &camerabin_photography_info); -} - -GST_BOILERPLATE_FULL (GstCameraBin, gst_camerabin, GstPipeline, - GST_TYPE_PIPELINE, camerabin_init_interfaces); - -/* - * static helper functions implementation - */ - -/* - * camerabin_setup_src_elements: - * @camera: camerabin object - * - * This function updates camerabin capsfilters according - * to fps, resolution and zoom that have been configured - * to camerabin. - */ -static void -camerabin_setup_src_elements (GstCameraBin * camera) -{ - GstStructure *st; - GstCaps *new_caps; - gboolean detect_framerate = FALSE; - - if (!camera->view_finder_caps) { - st = gst_structure_from_string (CAMERABIN_DEFAULT_VF_CAPS, NULL); - } else { - st = gst_structure_copy (gst_caps_get_structure (camera->view_finder_caps, - 0)); - } - - if (camera->width > 0 && camera->height > 0) { - gst_structure_set (st, - "width", G_TYPE_INT, camera->width, - "height", G_TYPE_INT, camera->height, NULL); - } - - if (camera->fps_n > 0 && camera->fps_d > 0) { - if (camera->night_mode) { - GST_WARNING_OBJECT (camera, - "night mode, lowest allowed fps will be forced"); - camera->pre_night_fps_n = camera->fps_n; - camera->pre_night_fps_d = camera->fps_d; - detect_framerate = TRUE; - } else { - gst_structure_set (st, - "framerate", GST_TYPE_FRACTION, camera->fps_n, camera->fps_d, NULL); - new_caps = gst_caps_new_full (st, NULL); - } - } else { - GST_DEBUG_OBJECT (camera, "no framerate specified"); - detect_framerate = TRUE; - } - - if (detect_framerate) { - GST_DEBUG_OBJECT (camera, "detecting allowed framerate"); - /* Remove old framerate if any */ - if (gst_structure_has_field (st, "framerate")) { - gst_structure_remove_field (st, "framerate"); - } - new_caps = gst_caps_new_full (st, NULL); - - /* Set allowed framerate for the resolution */ - gst_camerabin_set_allowed_framerate (camera, new_caps); - } - - /* Set default zoom method */ - g_object_set (camera->src_zoom_scale, "method", - CAMERABIN_DEFAULT_ZOOM_METHOD, NULL); - - gst_caps_replace (&camera->view_finder_caps, new_caps); - - /* Set caps for view finder mode */ - gst_camerabin_set_capsfilter_caps (camera, camera->view_finder_caps); -} - -/* - * camerabin_create_src_elements: - * @camera: camerabin object - * - * This function creates and links upstream side elements for camerabin. - * videosrc ! cspconv ! capsfilter ! crop ! scale ! capsfilter ! out-sel ! - * - * Returns: TRUE, if elements were successfully created, FALSE otherwise - */ -static gboolean -camerabin_create_src_elements (GstCameraBin * camera) -{ - gboolean ret = FALSE; - GstBin *cbin = GST_BIN (camera); - gchar *driver_name = NULL; - - if (camera->user_vid_src) { - camera->src_vid_src = camera->user_vid_src; - - if (!gst_camerabin_add_element (cbin, camera->src_vid_src)) { - camera->src_vid_src = NULL; - goto done; - } - } else if (!(camera->src_vid_src = - gst_camerabin_create_and_add_element (cbin, DEFAULT_SRC_VID_SRC))) - goto done; -#ifdef USE_COLOR_CONVERTER - if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace")) - goto done; -#endif - if (!(camera->src_filter = - gst_camerabin_create_and_add_element (cbin, "capsfilter"))) - goto done; - if (!(camera->src_zoom_crop = - gst_camerabin_create_and_add_element (cbin, "videocrop"))) - goto done; - if (!(camera->src_zoom_scale = - gst_camerabin_create_and_add_element (cbin, "videoscale"))) - goto done; - if (!(camera->src_zoom_filter = - gst_camerabin_create_and_add_element (cbin, "capsfilter"))) - goto done; - if (!(camera->src_out_sel = - gst_camerabin_create_and_add_element (cbin, "output-selector"))) - goto done; - - camera->srcpad_zoom_filter = - gst_element_get_static_pad (camera->src_zoom_filter, "src"); - - /* Set default "driver-name" for v4l2camsrc if not set */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src), - "driver-name")) { - g_object_get (G_OBJECT (camera->src_vid_src), "driver-name", - &driver_name, NULL); - if (!driver_name) { - g_object_set (G_OBJECT (camera->src_vid_src), "driver-name", - DEFAULT_V4L2CAMSRC_DRIVER_NAME, NULL); - } - } - - ret = TRUE; -done: - return ret; -} - -/* - * camerabin_setup_view_elements: - * @camera: camerabin object - * - * This function configures properties for view finder sink element. - */ -static void -camerabin_setup_view_elements (GstCameraBin * camera) -{ - GST_DEBUG_OBJECT (camera, "setting view finder properties"); - g_object_set (G_OBJECT (camera->view_in_sel), "select-all", TRUE, NULL); - /* Set properties for view finder sink */ - /* Find the actual sink if using bin like autovideosink */ - if (GST_IS_BIN (camera->view_sink)) { - GList *child = NULL, *children = GST_BIN_CHILDREN (camera->view_sink); - for (child = children; child != NULL; child = g_list_next (children)) { - GObject *ch = G_OBJECT (child->data); - if (g_object_class_find_property (G_OBJECT_GET_CLASS (ch), "sync")) { - g_object_set (G_OBJECT (ch), "sync", FALSE, "qos", FALSE, "async", - FALSE, NULL); - } - } - } else { - g_object_set (G_OBJECT (camera->view_sink), "sync", FALSE, "qos", FALSE, - "async", FALSE, NULL); - } -} - -/* - * camerabin_create_view_elements: - * @camera: camerabin object - * - * This function creates and links downstream side elements for camerabin. - * ! scale ! cspconv ! view finder sink - * - * Returns: TRUE, if elements were successfully created, FALSE otherwise - */ -static gboolean -camerabin_create_view_elements (GstCameraBin * camera) -{ - const GList *pads; - - if (!(camera->view_in_sel = - gst_camerabin_create_and_add_element (GST_BIN (camera), - "input-selector"))) { - goto error; - } - - /* Look for recently added input selector sink pad, we need to release it later */ - pads = GST_ELEMENT_PADS (camera->view_in_sel); - while (pads != NULL - && (GST_PAD_DIRECTION (GST_PAD (pads->data)) != GST_PAD_SINK)) { - pads = g_list_next (pads); - } - camera->pad_view_img = GST_PAD (pads->data); - - if (!(camera->view_scale = - gst_camerabin_create_and_add_element (GST_BIN (camera), - "videoscale"))) { - goto error; - } -#ifdef USE_COLOR_CONVERTER - if (!gst_camerabin_create_and_add_element (GST_BIN (camera), - "ffmpegcolorspace")) { - goto error; - } -#endif - if (camera->user_vf_sink) { - camera->view_sink = camera->user_vf_sink; - if (!gst_camerabin_add_element (GST_BIN (camera), camera->view_sink)) { - goto error; - } - } else if (!(camera->view_sink = - gst_camerabin_create_and_add_element (GST_BIN (camera), - DEFAULT_VIEW_SINK))) { - goto error; - } - - return TRUE; -error: - return FALSE; -} - -/* - * camerabin_create_elements: - * @camera: camerabin object - * - * This function creates and links all elements for camerabin, - * - * Returns: TRUE, if elements were successfully created, FALSE otherwise - */ -static gboolean -camerabin_create_elements (GstCameraBin * camera) -{ - gboolean ret = FALSE; - GstPadLinkReturn link_ret = GST_PAD_LINK_REFUSED; - GstPad *unconnected_pad; - - GST_LOG_OBJECT (camera, "creating elems"); - - /* Create "src" elements */ - if (!camerabin_create_src_elements (camera)) { - goto done; - } - - /* Add image bin */ - camera->pad_src_img = - gst_element_get_request_pad (camera->src_out_sel, "src%d"); - if (!gst_camerabin_add_element (GST_BIN (camera), camera->imgbin)) { - goto done; - } - gst_pad_add_buffer_probe (camera->pad_src_img, - G_CALLBACK (gst_camerabin_have_img_buffer), camera); - - /* Create view finder elements, this also links it to image bin */ - if (!camerabin_create_view_elements (camera)) { - GST_WARNING_OBJECT (camera, "creating view failed"); - goto done; - } - - /* Link output selector ! view_finder */ - camera->pad_src_view = - gst_element_get_request_pad (camera->src_out_sel, "src%d"); - camera->pad_view_src = - gst_element_get_request_pad (camera->view_in_sel, "sink%d"); - link_ret = gst_pad_link (camera->pad_src_view, camera->pad_view_src); - if (GST_PAD_LINK_FAILED (link_ret)) { - GST_ELEMENT_ERROR (camera, CORE, NEGOTIATION, - ("linking view finder failed"), (NULL)); - goto done; - } - - /* Set view finder active as default */ - g_object_set (G_OBJECT (camera->src_out_sel), "active-pad", - camera->pad_src_view, NULL); - - /* Add video bin */ - camera->pad_src_vid = - gst_element_get_request_pad (camera->src_out_sel, "src%d"); - if (!gst_camerabin_add_element (GST_BIN (camera), camera->vidbin)) { - goto done; - } - gst_pad_add_buffer_probe (camera->pad_src_vid, - G_CALLBACK (gst_camerabin_have_vid_buffer), camera); - - /* Link video bin ! view finder */ - // unconnected_pad = gst_bin_find_unlinked_pad (GST_BIN (camera), GST_PAD_SRC); - unconnected_pad = gst_bin_find_unconnected_pad (GST_BIN (camera), GST_PAD_SRC); - camera->pad_view_vid = - gst_element_get_request_pad (camera->view_in_sel, "sink%d"); - link_ret = gst_pad_link (unconnected_pad, camera->pad_view_vid); - gst_object_unref (unconnected_pad); - if (GST_PAD_LINK_FAILED (link_ret)) { - GST_ELEMENT_ERROR (camera, CORE, NEGOTIATION, (NULL), - ("linking video bin and view finder failed")); - goto done; - } - - ret = TRUE; - -done: - - if (FALSE == ret) - camerabin_destroy_elements (camera); - - return ret; -} - -/* - * camerabin_destroy_elements: - * @camera: camerabin object - * - * This function removes all elements from camerabin. - */ -static void -camerabin_destroy_elements (GstCameraBin * camera) -{ - GST_DEBUG_OBJECT (camera, "destroying elements"); - - /* Release request pads */ - if (camera->pad_view_vid) { - gst_element_release_request_pad (camera->view_in_sel, camera->pad_view_vid); - camera->pad_view_vid = NULL; - } - if (camera->pad_src_vid) { - gst_element_release_request_pad (camera->src_out_sel, camera->pad_src_vid); - camera->pad_src_vid = NULL; - } - if (camera->pad_view_img) { - gst_element_release_request_pad (camera->view_in_sel, camera->pad_view_img); - camera->pad_view_img = NULL; - } - if (camera->pad_src_img) { - gst_element_release_request_pad (camera->src_out_sel, camera->pad_src_img); - camera->pad_src_img = NULL; - } - if (camera->pad_view_src) { - gst_element_release_request_pad (camera->view_in_sel, camera->pad_view_src); - camera->pad_view_src = NULL; - } - if (camera->pad_src_view) { - gst_element_release_request_pad (camera->src_out_sel, camera->pad_src_view); - camera->pad_src_view = NULL; - } - - camera->view_sink = NULL; - camera->view_scale = NULL; - camera->view_in_sel = NULL; - - camera->src_out_sel = NULL; - camera->src_filter = NULL; - camera->src_zoom_crop = NULL; - camera->src_zoom_scale = NULL; - camera->src_zoom_filter = NULL; - camera->src_vid_src = NULL; - - camera->active_bin = NULL; - - /* Remove elements */ - gst_camerabin_remove_elements_from_bin (GST_BIN (camera)); -} - -/* - * camerabin_dispose_elements: - * @camera: camerabin object - * - * This function releases all allocated camerabin resources. - */ -static void -camerabin_dispose_elements (GstCameraBin * camera) -{ - if (camera->capture_mutex) { - g_mutex_free (camera->capture_mutex); - camera->capture_mutex = NULL; - } - if (camera->cond) { - g_cond_free (camera->cond); - camera->cond = NULL; - } - if (camera->filename) { - g_string_free (camera->filename, TRUE); - camera->filename = NULL; - } - /* Unref user set elements */ - if (camera->user_vf_sink) { - gst_object_unref (camera->user_vf_sink); - camera->user_vf_sink = NULL; - } - if (camera->user_vid_src) { - gst_object_unref (camera->user_vid_src); - camera->user_vid_src = NULL; - } - - if (camera->image_capture_caps) { - gst_caps_unref (camera->image_capture_caps); - camera->image_capture_caps = NULL; - } - - if (camera->view_finder_caps) { - gst_caps_unref (camera->view_finder_caps); - camera->view_finder_caps = NULL; - } - - if (camera->allowed_caps) { - gst_caps_unref (camera->allowed_caps); - camera->allowed_caps = NULL; - } -} - -/* - * gst_camerabin_image_capture_continue: - * @camera: camerabin object - * @filename: new filename set by user - * @cont: TRUE to continue image capture, FALSE otherwise - * - * Check if user wants to continue image capturing by using g_signal. - */ -static void -gst_camerabin_image_capture_continue (GstCameraBin * camera, GString * filename, - gboolean * cont) -{ - GST_DEBUG_OBJECT (camera, "emitting img_done signal, filename: %s", - filename->str); - g_signal_emit (G_OBJECT (camera), camerabin_signals[IMG_DONE_SIGNAL], 0, - filename, cont); - - GST_DEBUG_OBJECT (camera, "emitted img_done, new filename:%s, continue:%d", - filename->str, *cont); -} - -/* - * gst_camerabin_change_mode: - * @camera: camerabin object - * @mode: image or video mode - * - * Change camerabin mode between image and video capture. - * Changing mode will stop ongoing capture. - */ -static void -gst_camerabin_change_mode (GstCameraBin * camera, gint mode) -{ - if (camera->mode != mode || !camera->active_bin) { - GST_DEBUG_OBJECT (camera, "setting mode: %d", mode); - /* Interrupt ongoing capture */ - gst_camerabin_do_stop (camera); - camera->mode = mode; - if (camera->active_bin) { - gst_element_set_state (camera->active_bin, GST_STATE_NULL); - } - if (camera->mode == MODE_IMAGE) { - camera->active_bin = camera->imgbin; - } else if (camera->mode == MODE_VIDEO) { - camera->active_bin = camera->vidbin; - } - gst_camerabin_reset_to_view_finder (camera); - } -} - -/* - * gst_camerabin_change_filename: - * @camera: camerabin object - * @name: new filename for capture - * - * Change filename for image or video capture. - * Changing filename will stop ongoing capture. - */ -static void -gst_camerabin_change_filename (GstCameraBin * camera, const gchar * name) -{ - if (0 != strcmp (camera->filename->str, name)) { - GST_DEBUG_OBJECT (camera, "changing filename from %s to %s", - camera->filename->str, name); - /* Interrupt ongoing capture */ - gst_camerabin_do_stop (camera); - gst_camerabin_reset_to_view_finder (camera); - - if (camera->active_bin) { - g_object_set (G_OBJECT (camera->active_bin), "filename", name, NULL); - } - - g_string_assign (camera->filename, name); - } -} - -/* - * gst_camerabin_setup_zoom: - * @camera: camerabin object - * - * Apply zoom configured to camerabin to capture. - */ -static void -gst_camerabin_setup_zoom (GstCameraBin * camera) -{ - gint zoom; - gboolean done = FALSE; - - g_return_if_fail (camera != NULL); - g_return_if_fail (camera->src_zoom_crop != NULL); - - zoom = g_atomic_int_get (&camera->zoom); - - g_return_if_fail (zoom); - - if (GST_IS_ELEMENT (camera->src_vid_src) && - gst_element_implements_interface (camera->src_vid_src, - GST_TYPE_PHOTOGRAPHY)) { - /* Try setting (hardware) zoom using photography interface */ - GstPhotography *photo; - GstPhotoCaps pcaps; - - photo = GST_PHOTOGRAPHY (camera->src_vid_src); - pcaps = gst_photography_get_capabilities (photo); - - if (pcaps & GST_PHOTOGRAPHY_CAPS_ZOOM) { - done = gst_photography_set_zoom (photo, (gfloat) zoom / 100.0); - } - } - - if (!done) { - /* Update capsfilters to apply the (software) zoom */ - gint w2_crop = 0; - gint h2_crop = 0; - GstPad *pad_zoom_sink = NULL; - - GST_INFO_OBJECT (camera, "zoom: %d, orig size: %dx%d", zoom, - camera->width, camera->height); - - if (zoom != ZOOM_1X) { - w2_crop = (camera->width - (camera->width * ZOOM_1X / zoom)) / 2; - h2_crop = (camera->height - (camera->height * ZOOM_1X / zoom)) / 2; - } - - pad_zoom_sink = gst_element_get_static_pad (camera->src_zoom_crop, "sink"); - - GST_INFO_OBJECT (camera, - "sw cropping: left:%d, right:%d, top:%d, bottom:%d", w2_crop, w2_crop, - h2_crop, h2_crop); - - GST_PAD_STREAM_LOCK (pad_zoom_sink); - g_object_set (camera->src_zoom_crop, "left", w2_crop, "right", w2_crop, - "top", h2_crop, "bottom", h2_crop, NULL); - - GST_PAD_STREAM_UNLOCK (pad_zoom_sink); - gst_object_unref (pad_zoom_sink); - } - GST_LOG_OBJECT (camera, "zoom set"); -} - -/* - * gst_camerabin_get_allowed_input_caps: - * @camera: camerabin object - * - * Retrieve caps from videosrc describing formats it supports - * - * Returns: caps object from videosrc - */ -static GstCaps * -gst_camerabin_get_allowed_input_caps (GstCameraBin * camera) -{ - GstCaps *caps = NULL; - GstPad *pad = NULL, *peer_pad = NULL; - GstState state; - gboolean temp_videosrc_pause = FALSE; - GstElement *videosrc; - - g_return_val_if_fail (camera != NULL, NULL); - - videosrc = camera->src_vid_src ? camera->src_vid_src : camera->user_vid_src; - - if (!videosrc) { - GST_WARNING_OBJECT (camera, "no videosrc, can't get allowed caps"); - goto failed; - } - - if (camera->allowed_caps) { - GST_DEBUG_OBJECT (camera, "returning cached caps"); - goto done; - } - - pad = gst_element_get_static_pad (videosrc, "src"); - - if (!pad) { - GST_WARNING_OBJECT (camera, "no srcpad in videosrc"); - goto failed; - } - - state = GST_STATE (videosrc); - - /* Make this function work also in READY and NULL state */ - if (state == GST_STATE_READY || state == GST_STATE_NULL) { - GST_DEBUG_OBJECT (camera, "setting videosrc to paused temporarily"); - temp_videosrc_pause = TRUE; - peer_pad = gst_pad_get_peer (pad); - if (peer_pad) { - gst_pad_unlink (pad, peer_pad); - } - /* Set videosrc to PAUSED to open video device */ - gst_element_set_locked_state (videosrc, TRUE); - gst_element_set_state (videosrc, GST_STATE_PAUSED); - } - - camera->allowed_caps = gst_pad_get_caps (pad); - - /* Restore state and re-link if necessary */ - if (temp_videosrc_pause) { - GST_DEBUG_OBJECT (camera, "restoring videosrc state %d", state); - /* Reset videosrc to NULL state, some drivers seem to need this */ - gst_element_set_state (videosrc, GST_STATE_NULL); - gst_element_set_state (videosrc, state); - if (peer_pad) { - gst_pad_link (pad, peer_pad); - gst_object_unref (peer_pad); - } - gst_element_set_locked_state (videosrc, FALSE); - } - - gst_object_unref (pad); - -done: - if (camera->allowed_caps) { - caps = gst_caps_copy (camera->allowed_caps); - } -failed: - GST_INFO_OBJECT (camera, "allowed caps:%" GST_PTR_FORMAT, caps); - return caps; -} - -/* - * gst_camerabin_rewrite_tags_to_bin: - * @bin: bin holding tag setter elements - * @list: tag list to be written - * - * This function looks for certain tag setters from given bin - * and REPLACES ALL setter tags with given tag list - * - */ -static void -gst_camerabin_rewrite_tags_to_bin (GstBin * bin, const GstTagList * list) -{ - GstElement *setter; - GstElementFactory *setter_factory; - const gchar *klass; - GstIterator *iter; - GstIteratorResult res = GST_ITERATOR_OK; - gpointer data; - - iter = gst_bin_iterate_all_by_interface (bin, GST_TYPE_TAG_SETTER); - - while (res == GST_ITERATOR_OK || res == GST_ITERATOR_RESYNC) { - res = gst_iterator_next (iter, &data); - switch (res) { - case GST_ITERATOR_DONE: - break; - case GST_ITERATOR_RESYNC: - gst_iterator_resync (iter); - break; - case GST_ITERATOR_ERROR: - GST_WARNING ("error iterating tag setters"); - break; - case GST_ITERATOR_OK: - setter = GST_ELEMENT (data); - GST_LOG ("iterating tag setters: %" GST_PTR_FORMAT, setter); - setter_factory = gst_element_get_factory (setter); - klass = gst_element_factory_get_klass (setter_factory); - /* FIXME: check if tags should be written to all tag setters, - set tags only to Muxer elements for now */ - if (g_strrstr (klass, "Muxer")) { - GST_DEBUG ("replacement tags %" GST_PTR_FORMAT, list); - gst_tag_setter_merge_tags (GST_TAG_SETTER (setter), list, - GST_TAG_MERGE_REPLACE_ALL); - } - gst_object_unref (setter); - break; - default: - break; - } - } - - gst_iterator_free (iter); -} - -/* - * gst_camerabin_get_internal_tags: - * @camera: the camera bin element - * - * Returns tag list containing metadata from camerabin - * and it's elements - */ -static GstTagList * -gst_camerabin_get_internal_tags (GstCameraBin * camera) -{ - GstTagList *list = gst_tag_list_new (); - GstColorBalance *balance = NULL; - const GList *controls = NULL, *item; - GstColorBalanceChannel *channel; - gint min_value, max_value, mid_value, cur_value; - - - if (camera->active_bin == camera->vidbin) { - /* FIXME: check if internal video tag setting is needed */ - goto done; - } - - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - "image-width", camera->width, "image-height", camera->height, NULL); - - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - "capture-digital-zoom", camera->zoom, 100, NULL); - - if (gst_element_implements_interface (GST_ELEMENT (camera), - GST_TYPE_COLOR_BALANCE)) { - balance = GST_COLOR_BALANCE (camera); - } - - if (balance) { - controls = gst_color_balance_list_channels (balance); - } - for (item = controls; item; item = g_list_next (item)) { - channel = item->data; - min_value = channel->min_value; - max_value = channel->max_value; - /* the default value would probably better */ - mid_value = min_value + ((max_value - min_value) / 2); - cur_value = gst_color_balance_get_value (balance, channel); - - if (!strcasecmp (channel->label, "brightness")) { - /* The value of brightness. The unit is the APEX value (Additive System of Photographic Exposure). - * Ordinarily it is given in the range of -99.99 to 99.99. Note that - * if the numerator of the recorded value is 0xFFFFFFFF, Unknown shall be indicated. - * - * BrightnessValue (Bv) = log2 ( B/NK ) - * Note that: B:cd/cm² (candela per square centimeter), N,K: constant - * - * http://johnlind.tripod.com/science/scienceexposure.html - * - */ - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - "capture-brightness", cur_value, 1, NULL); - } else if (!strcasecmp (channel->label, "contrast")) { - /* 0 = Normal, 1 = Soft, 2 = Hard */ - - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - "capture-contrast", - (cur_value == mid_value) ? 0 : ((cur_value < mid_value) ? 1 : 2), - NULL); - } else if (!strcasecmp (channel->label, "gain")) { - /* 0 = Normal, 1 = Low Up, 2 = High Up, 3 = Low Down, 4 = Hight Down */ - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - "capture-gain", - (guint) (cur_value == mid_value) ? 0 : ((cur_value < - mid_value) ? 1 : 3), NULL); - } else if (!strcasecmp (channel->label, "saturation")) { - /* 0 = Normal, 1 = Low, 2 = High */ - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - "capture-saturation", - (cur_value == mid_value) ? 0 : ((cur_value < mid_value) ? 1 : 2), - NULL); - } - } - -done: - - return list; -} - -/* - * gst_camerabin_rewrite_tags: - * @camera: the camera bin element - * - * Merges application set tags to camerabin internal tags, - * and writes them using image or video bin tag setters. - */ -static void -gst_camerabin_rewrite_tags (GstCameraBin * camera) -{ - const GstTagList *app_tag_list = NULL; - GstTagList *list = NULL; - - /* Get application set tags */ - app_tag_list = gst_tag_setter_get_tag_list (GST_TAG_SETTER (camera)); - - /* Get tags from camerabin and it's elements */ - list = gst_camerabin_get_internal_tags (camera); - - if (app_tag_list) { - gst_tag_list_insert (list, app_tag_list, GST_TAG_MERGE_REPLACE); - } - - /* Write tags */ - gst_camerabin_rewrite_tags_to_bin (GST_BIN (camera->active_bin), list); - - gst_tag_list_free (list); -} - -/* - * gst_camerabin_set_capsfilter_caps: - * @camera: camerabin object - * @new_caps: pointer to caps object to set - * - * Set given caps to camerabin capsfilters. - */ -static void -gst_camerabin_set_capsfilter_caps (GstCameraBin * camera, GstCaps * new_caps) -{ - GstStructure *st; - - GST_INFO_OBJECT (camera, "new_caps:%" GST_PTR_FORMAT, new_caps); - - st = gst_caps_get_structure (new_caps, 0); - - gst_structure_get_int (st, "width", &camera->width); - gst_structure_get_int (st, "height", &camera->height); - - if (gst_structure_has_field (st, "framerate")) { - gst_structure_get_fraction (st, "framerate", &camera->fps_n, - &camera->fps_d); - } - - /* Update zoom */ - gst_camerabin_setup_zoom (camera); - - /* Update capsfilters */ - g_object_set (G_OBJECT (camera->src_filter), "caps", new_caps, NULL); - g_object_set (G_OBJECT (camera->src_zoom_filter), "caps", new_caps, NULL); -} - -/* - * img_capture_prepared: - * @data: camerabin object - * - * Callback which is called after image capture has been prepared. - */ -static void -img_capture_prepared (gpointer data) -{ - GstCameraBin *camera = GST_CAMERABIN (data); - - GST_INFO_OBJECT (camera, "image capture prepared"); - - if (camera->image_capture_caps) { - /* Set capsfilters to match arriving image data */ - gst_camerabin_set_capsfilter_caps (camera, camera->image_capture_caps); - } - - g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE, - "active-pad", camera->pad_src_img, NULL); - gst_camerabin_rewrite_tags (camera); - gst_element_set_state (GST_ELEMENT (camera->imgbin), GST_STATE_PLAYING); -} - -/* - * gst_camerabin_start_image_capture: - * @camera: camerabin object - * - * Initiates image capture. - */ -static void -gst_camerabin_start_image_capture (GstCameraBin * camera) -{ - GstStateChangeReturn state_ret; - gboolean wait_for_prepare = FALSE; - gint width = 0, height = 0, fps_n = 0, fps_d = 0; - GstStructure *st; - - GST_INFO_OBJECT (camera, "starting image capture"); - - if (GST_IS_ELEMENT (camera->src_vid_src) && - gst_element_implements_interface (camera->src_vid_src, - GST_TYPE_PHOTOGRAPHY)) { - /* Start image capture preparations using photography iface */ - wait_for_prepare = TRUE; - g_mutex_lock (camera->capture_mutex); - if (camera->image_capture_caps) { - st = gst_caps_get_structure (camera->image_capture_caps, 0); - } else { - st = gst_caps_get_structure (camera->view_finder_caps, 0); - } - gst_structure_get_int (st, "width", &width); - gst_structure_get_int (st, "height", &height); - gst_structure_get_fraction (st, "framerate", &fps_n, &fps_d); - /* Set image capture resolution and frame rate */ - g_signal_emit_by_name (camera->src_vid_src, "user-res-fps", - width, height, fps_n, fps_d, 0); - - /* Enable still image capture mode in v4l2camsrc */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src), - "capture-mode")) { - g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 1, NULL); - } - - /* Start preparations for image capture */ - gst_photography_prepare_for_capture (GST_PHOTOGRAPHY (camera->src_vid_src), - (GstPhotoCapturePrepared) img_capture_prepared, camera); - camera->capturing = TRUE; - g_mutex_unlock (camera->capture_mutex); - } - - if (!wait_for_prepare) { - gst_camerabin_rewrite_tags (camera); - state_ret = gst_element_set_state (camera->imgbin, GST_STATE_PLAYING); - if (state_ret != GST_STATE_CHANGE_FAILURE) { - g_mutex_lock (camera->capture_mutex); - g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", TRUE, - "active-pad", camera->pad_src_img, NULL); - camera->capturing = TRUE; - g_mutex_unlock (camera->capture_mutex); - } else { - GST_WARNING_OBJECT (camera, "imagebin state change failed"); - gst_element_set_state (camera->imgbin, GST_STATE_NULL); - } - } -} - -/* - * gst_camerabin_start_video_recording: - * @camera: camerabin object - * - * Initiates video recording. - */ -static void -gst_camerabin_start_video_recording (GstCameraBin * camera) -{ - GstStateChangeReturn state_ret; - /* FIXME: how to ensure resolution and fps is supported by CPU? - * use a queue overrun signal? - */ - GST_INFO_OBJECT (camera, "starting video capture"); - - gst_camerabin_rewrite_tags (camera); - - /* Pause the pipeline in order to distribute new clock in paused_to_playing */ - /* audio src timestamps will be 0 without state change to READY. ??? */ - gst_element_set_state (GST_ELEMENT (camera), GST_STATE_READY); - gst_element_set_locked_state (camera->vidbin, FALSE); - state_ret = gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED); - - if (state_ret != GST_STATE_CHANGE_FAILURE) { - g_mutex_lock (camera->capture_mutex); - g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE, - "active-pad", camera->pad_src_vid, NULL); - - /* Enable video mode in v4l2camsrc */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src), - "capture-mode")) { - g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 2, NULL); - } - - gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING); - gst_element_set_locked_state (camera->vidbin, TRUE); - camera->capturing = TRUE; - g_mutex_unlock (camera->capture_mutex); - } else { - GST_WARNING_OBJECT (camera, "videobin state change failed"); - gst_element_set_state (camera->vidbin, GST_STATE_NULL); - gst_camerabin_reset_to_view_finder (camera); - } -} - -/* - * gst_camerabin_send_video_eos: - * @camera: camerabin object - * - * Generate and send eos event to video bin in order to - * finish recording properly. - */ -static void -gst_camerabin_send_video_eos (GstCameraBin * camera) -{ - GstPad *videopad; - - g_return_if_fail (camera != NULL); - - /* Send eos event to video bin */ - GST_INFO_OBJECT (camera, "sending eos to videobin"); - videopad = gst_element_get_static_pad (camera->vidbin, "sink"); - gst_pad_send_event (videopad, gst_event_new_eos ()); - gst_object_unref (videopad); -} - -/* - * image_pad_blocked: - * @pad: pad to block/unblock - * @blocked: TRUE to block, FALSE to unblock - * @u_data: camera bin object - * - * Sends eos event to image bin if blocking pad leading to image bin. - * The pad will be unblocked when image bin posts eos message. - */ -static void -image_pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data) -{ - GstCameraBin *camera; - - camera = (GstCameraBin *) user_data; - - GST_DEBUG_OBJECT (camera, "%s %s:%s", - blocked ? "blocking" : "unblocking", GST_DEBUG_PAD_NAME (pad)); - - if (blocked && (pad == camera->pad_src_img)) { - /* Send eos and block until image bin reaches eos */ - GST_DEBUG_OBJECT (camera, "sending eos to image bin"); - gst_element_send_event (camera->imgbin, gst_event_new_eos ()); - } -} - -/* - * gst_camerabin_have_img_buffer: - * @pad: output-selector src pad leading to image bin - * @buffer: still image frame - * @u_data: camera bin object - * - * Buffer probe called before sending each buffer to image bin. - * - * First buffer is always passed directly to image bin. Then pad - * is blocked in order to interleave buffers with eos events. - * Interleaving eos events and buffers is needed when we have - * decoupled elements in the image bin capture pipeline. - * After image bin posts eos message, then pad is unblocked. - * Next, image bin is changed to READY state in order to save the - * file and the application is allowed to decide whether to - * continue image capture. If yes, only then the next buffer is - * passed to image bin. - */ -static gboolean -gst_camerabin_have_img_buffer (GstPad * pad, GstBuffer * buffer, - gpointer u_data) -{ - GstCameraBin *camera = (GstCameraBin *) u_data; - gboolean ret = TRUE; - - GST_LOG ("got buffer #%d %p with size %d", camera->num_img_buffers, - buffer, GST_BUFFER_SIZE (buffer)); - - /* Image filename should be set by now */ - if (g_str_equal (camera->filename->str, "")) { - GST_DEBUG_OBJECT (camera, "filename not set, dropping buffer"); - ret = FALSE; - goto done; - } - - /* Check for first buffer after capture start, we want to - pass it forward directly. */ - if (!camera->num_img_buffers) { - /* Restore filter caps for view finder mode if necessary. - The v4l2camsrc switches automatically to view finder - resolution after hi-res still image capture. */ - if (camera->image_capture_caps) { - gst_camerabin_set_capsfilter_caps (camera, camera->view_finder_caps); - } - goto done; - } - - /* Close the file of saved image */ - gst_element_set_state (camera->imgbin, GST_STATE_READY); - - /* Check if the application wants to continue */ - gst_camerabin_image_capture_continue (camera, camera->filename, &ret); - - if (ret && !camera->stop_requested) { - GST_DEBUG_OBJECT (camera, "capturing image \"%s\"", camera->filename->str); - g_object_set (G_OBJECT (camera->imgbin), "filename", - camera->filename->str, NULL); - gst_element_set_state (camera->imgbin, GST_STATE_PLAYING); - } else { - GST_DEBUG_OBJECT (camera, "not continuing (cont:%d, stop_req:%d)", - ret, camera->stop_requested); - /* Reset filename to force application set new filename */ - g_string_assign (camera->filename, ""); - - /* Block dataflow to the output-selector to show preview image in - view finder. Continue and unblock when capture is stopped */ - gst_pad_set_blocked_async (camera->srcpad_zoom_filter, TRUE, - (GstPadBlockCallback) image_pad_blocked, camera); - ret = FALSE; /* Drop the buffer */ - - g_mutex_lock (camera->capture_mutex); - camera->capturing = FALSE; - g_cond_signal (camera->cond); - g_mutex_unlock (camera->capture_mutex); - } - -done: - - if (ret) { - camera->num_img_buffers++; - /* Block when next buffer arrives, we want to push eos event - between frames and make sure that eos reaches the filesink - before processing the next buffer. */ - gst_pad_set_blocked_async (pad, TRUE, - (GstPadBlockCallback) image_pad_blocked, camera); - } - - return ret; -} - -/* - * gst_camerabin_have_vid_buffer: - * @pad: output-selector src pad leading to video bin - * @buffer: buffer pushed to the pad - * @u_data: camerabin object - * - * Buffer probe for src pad leading to video bin. - * Sends eos event to video bin if stop requested and drops - * all buffers after this. - */ -static gboolean -gst_camerabin_have_vid_buffer (GstPad * pad, GstBuffer * buffer, - gpointer u_data) -{ - GstCameraBin *camera = (GstCameraBin *) u_data; - gboolean ret = TRUE; - GST_LOG ("got video buffer %p with size %d", - buffer, GST_BUFFER_SIZE (buffer)); - if (camera->stop_requested) { - gst_camerabin_send_video_eos (camera); - ret = FALSE; /* Drop buffer */ - } - - return ret; -} - -/* - * gst_camerabin_reset_to_view_finder: - * @camera: camerabin object - * - * Stop capturing and set camerabin to view finder mode. - * Reset capture counters and flags. - */ -static void -gst_camerabin_reset_to_view_finder (GstCameraBin * camera) -{ - GstStateChangeReturn state_ret; - GST_DEBUG_OBJECT (camera, "resetting"); - - /* Set active bin to READY state */ - if (camera->active_bin) { - state_ret = gst_element_set_state (camera->active_bin, GST_STATE_READY); - if (state_ret == GST_STATE_CHANGE_FAILURE) { - GST_WARNING_OBJECT (camera, "state change failed"); - gst_element_set_state (camera->active_bin, GST_STATE_NULL); - camera->active_bin = NULL; - } - } - - /* Reset counters and flags */ - camera->num_img_buffers = 0; - camera->stop_requested = FALSE; - camera->paused = FALSE; - - if (camera->src_out_sel) { - /* Set selector to forward data to view finder */ - g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE, - "active-pad", camera->pad_src_view, NULL); - } - - /* Unblock, if dataflow to output-selector is blocked due to image preview */ - if (camera->srcpad_zoom_filter && - gst_pad_is_blocked (camera->srcpad_zoom_filter)) { - gst_pad_set_blocked_async (camera->srcpad_zoom_filter, FALSE, - (GstPadBlockCallback) image_pad_blocked, camera); - } - /* Unblock, if dataflow to image bin is blocked due to waiting for eos */ - if (camera->pad_src_img && gst_pad_is_blocked (camera->pad_src_img)) { - gst_pad_set_blocked_async (camera->pad_src_img, FALSE, - (GstPadBlockCallback) image_pad_blocked, camera); - } - - /* Enable view finder mode in v4l2camsrc */ - if (camera->src_vid_src && - g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src), - "capture-mode")) { - g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 0, NULL); - } - - GST_DEBUG_OBJECT (camera, "reset done"); -} - -/* - * gst_camerabin_do_stop: - * @camera: camerabin object - * - * Raise flag to indicate to image and video bin capture stop. - * Stopping paused video recording handled as a special case. - * Wait for ongoing capturing to finish. - */ -static void -gst_camerabin_do_stop (GstCameraBin * camera) -{ - g_mutex_lock (camera->capture_mutex); - if (camera->capturing) { - GST_DEBUG_OBJECT (camera, "mark stop"); - camera->stop_requested = TRUE; - - /* Take special care when stopping paused video capture */ - if ((camera->active_bin == camera->vidbin) && camera->paused) { - /* Send eos event to video bin before setting it to playing */ - gst_camerabin_send_video_eos (camera); - /* We must change to playing now in order to get video bin eos events - and buffered data through and finish recording properly */ - gst_element_set_state (GST_ELEMENT (camera->vidbin), GST_STATE_PLAYING); - camera->paused = FALSE; - } - - GST_DEBUG_OBJECT (camera, "waiting for capturing to finish"); - g_cond_wait (camera->cond, camera->capture_mutex); - GST_DEBUG_OBJECT (camera, "capturing finished"); - } - g_mutex_unlock (camera->capture_mutex); -} - -/* - * gst_camerabin_default_signal_img_done: - * @camera: camerabin object - * @fname: new filename - * - * Default handler for #GstCameraBin::img-done signal, - * stops always capture. - * - * Returns: FALSE always - */ -static gboolean -gst_camerabin_default_signal_img_done (GstCameraBin * camera, GString * fname) -{ - return FALSE; -} - -/* - * gst_camerabin_set_allowed_framerate: - * @camera: camerabin object - * @filter_caps: update allowed framerate to these caps - * - * Find allowed frame rate from video source that matches with - * resolution in @filter_caps. Set found frame rate to @filter_caps. - */ -static void -gst_camerabin_set_allowed_framerate (GstCameraBin * camera, - GstCaps * filter_caps) -{ - GstStructure *structure; - GstCaps *allowed_caps = NULL, *intersect = NULL; - const GValue *framerate = NULL; - guint caps_size, i; - - /* Get supported caps from video src that matches with new filter caps */ - GST_INFO_OBJECT (camera, "filter caps:%" GST_PTR_FORMAT, filter_caps); - allowed_caps = gst_camerabin_get_allowed_input_caps (camera); - intersect = gst_caps_intersect (allowed_caps, filter_caps); - GST_INFO_OBJECT (camera, "intersect caps:%" GST_PTR_FORMAT, intersect); - - /* Find the best framerate from the caps */ - caps_size = gst_caps_get_size (intersect); - for (i = 0; i < caps_size; i++) { - structure = gst_caps_get_structure (intersect, i); - framerate = - gst_camerabin_find_better_framerate (camera, structure, framerate); - } - - if (GST_VALUE_HOLDS_FRACTION (framerate)) { - gst_caps_set_simple (filter_caps, - "framerate", GST_TYPE_FRACTION, - gst_value_get_fraction_numerator (framerate), - gst_value_get_fraction_denominator (framerate), NULL); - } - - if (allowed_caps) { - gst_caps_unref (allowed_caps); - } - if (intersect) { - gst_caps_unref (intersect); - } -} - - -/** - * get_srcpad_current_format: - * @element: element to get the format from - * - * Helper function to get the negotiated fourcc - * format from @element src pad. - * - * Returns: negotiated format (fourcc), 0 if not found - */ -static guint32 -get_srcpad_current_format (GstElement * element) -{ - GstPad *srcpad = NULL; - GstCaps *srccaps = NULL; - GstStructure *structure; - guint32 format = 0; - - g_return_val_if_fail (element != NULL, 0); - - if ((srcpad = gst_element_get_static_pad (element, "src")) == NULL) { - goto no_pad; - } - - if ((srccaps = gst_pad_get_negotiated_caps (srcpad)) == NULL) { - goto no_caps; - } - - GST_LOG ("negotiated caps %" GST_PTR_FORMAT, srccaps); - - structure = gst_caps_get_structure (srccaps, 0); - if (gst_structure_has_field (structure, "format")) { - gst_structure_get_fourcc (structure, "format", &format); - } - - gst_caps_unref (srccaps); -no_caps: - gst_object_unref (srcpad); -no_pad: - GST_DEBUG ("current format for %" GST_PTR_FORMAT ": %" GST_FOURCC_FORMAT, - element, GST_FOURCC_ARGS (format)); - return format; -} - -/* - * gst_camerabin_find_better_framerate: - * @camera: camerabin object - * @st: structure that contains framerate candidates - * @orig_framerate: best framerate so far - * - * Looks for framerate better than @orig_framerate from @st structure. - * In night mode lowest framerate is considered best, otherwise highest is - * best. - * - * Returns: @orig_framerate or better if found - */ -static const GValue * -gst_camerabin_find_better_framerate (GstCameraBin * camera, GstStructure * st, - const GValue * orig_framerate) -{ - const GValue *framerate = NULL; - guint i, i_best, list_size; - gint res, comparison; - - if (camera->night_mode) { - GST_LOG_OBJECT (camera, "finding min framerate"); - comparison = GST_VALUE_LESS_THAN; - } else { - GST_LOG_OBJECT (camera, "finding max framerate"); - comparison = GST_VALUE_GREATER_THAN; - } - - if (gst_structure_has_field (st, "framerate")) { - framerate = gst_structure_get_value (st, "framerate"); - /* Handle framerate lists */ - if (GST_VALUE_HOLDS_LIST (framerate)) { - list_size = gst_value_list_get_size (framerate); - GST_LOG_OBJECT (camera, "finding framerate from list"); - for (i = 0, i_best = 0; i < list_size; i++) { - res = gst_value_compare (gst_value_list_get_value (framerate, i), - gst_value_list_get_value (framerate, i_best)); - if (comparison == res) { - i_best = i; - } - } - GST_LOG_OBJECT (camera, "found best framerate from index %d", i_best); - framerate = gst_value_list_get_value (framerate, i_best); - } - /* Handle framerate ranges */ - if (GST_VALUE_HOLDS_FRACTION_RANGE (framerate)) { - if (camera->night_mode) { - GST_LOG_OBJECT (camera, "getting min framerate from range"); - framerate = gst_value_get_fraction_range_min (framerate); - } else { - GST_LOG_OBJECT (camera, "getting max framerate from range"); - framerate = gst_value_get_fraction_range_max (framerate); - } - } - } - - /* Check if we found better framerate */ - if (orig_framerate && framerate) { - res = gst_value_compare (orig_framerate, framerate); - if (comparison == res) { - GST_LOG_OBJECT (camera, "original framerate was the best"); - framerate = orig_framerate; - } - } - - return framerate; -} - -/* - * GObject callback functions implementation - */ - -static void -gst_camerabin_base_init (gpointer gclass) -{ - static GstElementDetails element_details = { - "Camera Bin", - "Generic/Bin/Camera", - "Handle lot of features present in DSC", - "Nokia Corporation \n" - "Edgard Lima " - }; - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - - gst_element_class_set_details (element_class, &element_details); -} - -static void -gst_camerabin_class_init (GstCameraBinClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBinClass *gstbin_class; - - gobject_class = G_OBJECT_CLASS (klass); - gstelement_class = GST_ELEMENT_CLASS (klass); - gstbin_class = GST_BIN_CLASS (klass); - - /* gobject */ - - gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_camerabin_dispose); - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_camerabin_finalize); - - gobject_class->set_property = gst_camerabin_set_property; - gobject_class->get_property = gst_camerabin_get_property; - - /** - * GstCameraBin:filename: - * - * Set filename for the still image capturing or video capturing. - */ - - g_object_class_install_property (gobject_class, ARG_FILENAME, - g_param_spec_string ("filename", "Filename", - "Filename of the image or video to save", "", G_PARAM_READWRITE)); - - /** - * GstCameraBin:mode: - * - * Set the mode of operation: still image capturing or video recording. - * Setting the mode will create and destroy image bin or video bin elements - * according to the mode. You can set this property at any time, changing - * the mode will stop ongoing capture. - */ - - g_object_class_install_property (gobject_class, ARG_MODE, - g_param_spec_enum ("mode", "Mode", - "The capture mode (still image capture or video recording)", - GST_TYPE_CAMERABIN_MODE, DEFAULT_MODE, G_PARAM_READWRITE)); - - /** - * GstCameraBin:mute: - * - * Mute audio in video recording mode. - * Set this property only when #GstCameraBin is in READY, PAUSED or PLAYING. - */ - - g_object_class_install_property (gobject_class, ARG_MUTE, - g_param_spec_boolean ("mute", "Mute", - "True to mute the recording. False to record with audio", - ARG_DEFAULT_MUTE, G_PARAM_READWRITE)); - - /** - * GstCameraBin:zoom: - * - * Set up the zoom applied to the frames. - * Set this property only when #GstCameraBin is in READY, PAUSED or PLAYING. - */ - - g_object_class_install_property (gobject_class, ARG_ZOOM, - g_param_spec_int ("zoom", "Zoom", - "The zoom. 100 for 1x, 200 for 2x and so on", - MIN_ZOOM, MAX_ZOOM, DEFAULT_ZOOM, G_PARAM_READWRITE)); - - /** - * GstCameraBin:imagepp: - * - * Set up an element to do image post processing. - * This property can only be set while #GstCameraBin is in NULL state. - * The ownership of the element will be taken by #GstCameraBin. - */ - g_object_class_install_property (gobject_class, ARG_IMAGE_POST, - g_param_spec_object ("imagepp", "Image post processing element", - "Image Post-Processing GStreamer element (default is NULL)", - GST_TYPE_ELEMENT, G_PARAM_READWRITE)); - - /** - * GstCameraBin:imageenc: - * - * Set up an image encoder (for example, jpegenc or pngenc) element. - * This property can only be set while #GstCameraBin is in NULL state. - * The ownership of the element will be taken by #GstCameraBin. - */ - - g_object_class_install_property (gobject_class, ARG_IMAGE_ENC, - g_param_spec_object ("imageenc", "Image encoder", - "Image encoder GStreamer element (default is jpegenc)", - GST_TYPE_ELEMENT, G_PARAM_READWRITE)); - - /** - * GstCameraBin:videopp: - * - * Set up an element to do video post processing. - * This property can only be set while #GstCameraBin is in NULL state. - * The ownership of the element will be taken by #GstCameraBin. - */ - - g_object_class_install_property (gobject_class, ARG_VIDEO_POST, - g_param_spec_object ("videopp", "Video post processing element", - "Video post processing GStreamer element (default is NULL)", - GST_TYPE_ELEMENT, G_PARAM_READWRITE)); - - /** - * GstCameraBin:videoenc: - * - * Set up a video encoder element. - * This property can only be set while #GstCameraBin is in NULL state. - * The ownership of the element will be taken by #GstCameraBin. - */ - - g_object_class_install_property (gobject_class, ARG_VIDEO_ENC, - g_param_spec_object ("videoenc", "Video encoder", - "Video encoder GStreamer element (default is theoraenc)", - GST_TYPE_ELEMENT, G_PARAM_READWRITE)); - - /** - * GstCameraBin:audioenc: - * - * Set up an audio encoder element. - * This property can only be set while #GstCameraBin is in NULL state. - * The ownership of the element will be taken by #GstCameraBin. - */ - - g_object_class_install_property (gobject_class, ARG_AUDIO_ENC, - g_param_spec_object ("audioenc", "Audio encoder", - "Audio encoder GStreamer element (default is vorbisenc)", - GST_TYPE_ELEMENT, G_PARAM_READWRITE)); - - /** - * GstCameraBin:videomux: - * - * Set up a video muxer element. - * This property can only be set while #GstCameraBin is in NULL state. - * The ownership of the element will be taken by #GstCameraBin. - */ - - g_object_class_install_property (gobject_class, ARG_VIDEO_MUX, - g_param_spec_object ("videomux", "Video muxer", - "Video muxer GStreamer element (default is oggmux)", - GST_TYPE_ELEMENT, G_PARAM_READWRITE)); - - /** - * GstCameraBin:vfsink: - * - * Set up a sink element to render frames in view finder. - * By default "autovideosink" will be the sink element. - * This property can only be set while #GstCameraBin is in NULL state. - * The ownership of the element will be taken by #GstCameraBin. - */ - - g_object_class_install_property (gobject_class, ARG_VF_SINK, - g_param_spec_object ("vfsink", "View finder sink", - "View finder sink GStreamer element (default is " DEFAULT_VIEW_SINK - ")", GST_TYPE_ELEMENT, G_PARAM_READWRITE)); - - /** - * GstCameraBin:videosrc: - * - * Set up a video source element. - * By default "v4l2src" will be the src element. - * This property can only be set while #GstCameraBin is in NULL state. - * The ownership of the element will be taken by #GstCameraBin. - */ - - g_object_class_install_property (gobject_class, ARG_VIDEO_SRC, - g_param_spec_object ("videosrc", "Video source element", - "Video source GStreamer element (default is " DEFAULT_SRC_VID_SRC ")", - GST_TYPE_ELEMENT, G_PARAM_READWRITE)); - /** - * GstCameraBin:audiosrc: - * - * Set up an audio source element. - * By default "pulsesrc" will be the source element. - * This property can only be set while #GstCameraBin is in NULL state. - * The ownership of the element will be taken by #GstCameraBin. - */ - - g_object_class_install_property (gobject_class, ARG_AUDIO_SRC, - g_param_spec_object ("audiosrc", "Audio source element", - "Audio source GStreamer element (default is pulsesrc)", - GST_TYPE_ELEMENT, G_PARAM_READWRITE)); - - /** - * GstCameraBin:inputcaps: - * - * The allowed modes of operation of the video source. Have in mind that it - * doesn't mean #GstCameraBin can operate in all those modes, - * it depends also on the other elements in the pipeline. Remember to - * gst_caps_unref after using it. - */ - - g_object_class_install_property (gobject_class, ARG_INPUT_CAPS, - g_param_spec_boxed ("inputcaps", "Input caps", - "The allowed modes of the video source operation", - GST_TYPE_CAPS, G_PARAM_READABLE)); - - /** - * GstCameraBin:filter-caps: - * - * Filter video source element caps using this property. - * This is an alternative to #GstCamerabin::user-res-fps action - * signal that allows more fine grained control of video source. - */ - - g_object_class_install_property (gobject_class, ARG_FILTER_CAPS, - g_param_spec_boxed ("filter-caps", "Filter caps", - "Capsfilter caps used to control video source operation", - GST_TYPE_CAPS, G_PARAM_READWRITE)); - - /** - * GstCameraBin::user-start: - * @camera: the camera bin element - * - * Starts image capture or video recording depending on the Mode. - * If there is a capture already going on, does nothing. - * Resumes video recording if it has been paused. - */ - - camerabin_signals[USER_START_SIGNAL] = - g_signal_new ("user-start", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstCameraBinClass, user_start), - NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - - /** - * GstCameraBin::user-stop: - * @camera: the camera bin element - * - * Stops still image preview, continuous image capture and video - * recording and returns to the view finder mode. - */ - - camerabin_signals[USER_STOP_SIGNAL] = - g_signal_new ("user-stop", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstCameraBinClass, user_stop), - NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - - /** - * GstCameraBin::user-pause: - * @camera: the camera bin element - * - * Pauses video recording or resumes paused video recording. - * If in image mode or not recording, does nothing. - */ - - camerabin_signals[USER_PAUSE_SIGNAL] = - g_signal_new ("user-pause", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstCameraBinClass, user_pause), - NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - - /** - * GstCameraBin::user-res-fps: - * @camera: the camera bin element - * @width: number of horizontal pixels - * @height: number of vertical pixels - * @fps_n: frames per second numerator - * @fps_d: frames per second denominator - * - * Changes the frame resolution and frames per second of the video source. - * The application must be aware of the resolutions supported by the camera. - * Supported resolutions and frame rates can be get using input-caps property. - * - * Setting @fps_n or @fps_d to 0 configures maximum framerate for the - * given resolution, unless in night mode when minimum is configured. - */ - - camerabin_signals[USER_RES_FPS_SIGNAL] = - g_signal_new ("user-res-fps", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstCameraBinClass, user_res_fps), - NULL, NULL, gst_camerabin_marshal_VOID__INT_INT_INT_INT, G_TYPE_NONE, 4, - G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); - - /** - * GstCameraBin::user-image-res: - * @camera: the camera bin element - * @width: number of horizontal pixels - * @height: number of vertical pixels - * - * Changes the resolution used for still image capture. - * Does not affect view finder mode and video recording. - * Use this action signal in PAUSED or PLAYING state. - */ - - camerabin_signals[USER_IMAGE_RES_SIGNAL] = - g_signal_new ("user-image-res", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstCameraBinClass, user_image_res), - NULL, NULL, gst_camerabin_marshal_VOID__INT_INT, G_TYPE_NONE, 2, - G_TYPE_INT, G_TYPE_INT); - - /** - * GstCameraBin::img-done: - * @camera: the camera bin element - * @filename: the name of the file just saved - * - * Signal emited when the file has just been saved. To continue taking - * pictures just update @filename and return TRUE, otherwise return FALSE. - * - * Don't call any #GstCameraBin method from this signal, if you do so there - * will be a deadlock. - */ - - camerabin_signals[IMG_DONE_SIGNAL] = - g_signal_new ("img-done", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstCameraBinClass, img_done), - g_signal_accumulator_true_handled, NULL, gst_marshal_BOOLEAN__POINTER, - G_TYPE_BOOLEAN, 1, G_TYPE_POINTER); - - klass->user_start = gst_camerabin_user_start; - klass->user_stop = gst_camerabin_user_stop; - klass->user_pause = gst_camerabin_user_pause; - klass->user_res_fps = gst_camerabin_user_res_fps; - klass->user_image_res = gst_camerabin_user_image_res; - - klass->img_done = gst_camerabin_default_signal_img_done; - - /* gstelement */ - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_camerabin_change_state); - - /* gstbin */ - /* override handle_message to peek when video or image bin reaches eos */ - gstbin_class->handle_message = - GST_DEBUG_FUNCPTR (gst_camerabin_handle_message_func); - -} - -/* initialize the new element - * instantiate pads and add them to element - * set functions - * initialize structure - */ -static void -gst_camerabin_init (GstCameraBin * camera, GstCameraBinClass * gclass) -{ - /* GstElementClass *klass = GST_ELEMENT_GET_CLASS (camera); */ - - camera->filename = g_string_new (""); - camera->mode = DEFAULT_MODE; - camera->num_img_buffers = 0; - camera->stop_requested = FALSE; - camera->paused = FALSE; - camera->capturing = FALSE; - camera->night_mode = FALSE; - - camera->width = DEFAULT_WIDTH; - camera->height = DEFAULT_HEIGHT; - camera->fps_n = DEFAULT_FPS_N; - camera->fps_d = DEFAULT_FPS_D; - - camera->image_capture_caps = NULL; - camera->view_finder_caps = NULL; - camera->allowed_caps = NULL; - - camera->zoom = DEFAULT_ZOOM; - - /* concurrency control */ - camera->capture_mutex = g_mutex_new (); - camera->cond = g_cond_new (); - - /* pad names for output and input selectors */ - camera->pad_src_view = NULL; - camera->pad_view_src = NULL; - camera->pad_src_img = NULL; - camera->pad_view_img = NULL; - camera->pad_src_vid = NULL; - camera->pad_view_vid = NULL; - camera->srcpad_zoom_filter = NULL; - - /* source elements */ - camera->src_vid_src = NULL; - camera->src_filter = NULL; - camera->src_zoom_crop = NULL; - camera->src_zoom_scale = NULL; - camera->src_zoom_filter = NULL; - camera->src_out_sel = NULL; - - camera->user_vf_sink = NULL; - - /* image capture bin */ - camera->imgbin = g_object_new (GST_TYPE_CAMERABIN_IMAGE, NULL); - gst_object_ref (camera->imgbin); - - /* video capture bin */ - camera->vidbin = g_object_new (GST_TYPE_CAMERABIN_VIDEO, NULL); - gst_object_ref (camera->vidbin); - - camera->active_bin = NULL; - - /* view finder elements */ - camera->view_in_sel = NULL; - camera->view_scale = NULL; - camera->view_sink = NULL; -} - -static void -gst_camerabin_dispose (GObject * object) -{ - GstCameraBin *camera; - - camera = GST_CAMERABIN (object); - - GST_DEBUG_OBJECT (camera, "disposing"); - - gst_element_set_state (camera->imgbin, GST_STATE_NULL); - gst_object_unref (camera->imgbin); - - gst_element_set_state (camera->vidbin, GST_STATE_NULL); - gst_object_unref (camera->vidbin); - - camerabin_destroy_elements (camera); - - camerabin_dispose_elements (camera); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gst_camerabin_finalize (GObject * object) -{ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_camerabin_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstCameraBin *camera = GST_CAMERABIN (object); - - switch (prop_id) { - case ARG_MUTE: - gst_camerabin_video_set_mute (GST_CAMERABIN_VIDEO (camera->vidbin), - g_value_get_boolean (value)); - break; - case ARG_ZOOM: - g_atomic_int_set (&camera->zoom, g_value_get_int (value)); - gst_camerabin_setup_zoom (camera); - break; - case ARG_MODE: - gst_camerabin_change_mode (camera, g_value_get_enum (value)); - break; - case ARG_FILENAME: - gst_camerabin_change_filename (camera, g_value_get_string (value)); - break; - case ARG_VIDEO_POST: - if (GST_STATE (camera->vidbin) != GST_STATE_NULL) { - GST_WARNING_OBJECT (camera, - "can't use set element until next video bin NULL to READY state change"); - } - gst_camerabin_video_set_post (GST_CAMERABIN_VIDEO (camera->vidbin), - g_value_get_object (value)); - break; - case ARG_VIDEO_ENC: - if (GST_STATE (camera->vidbin) != GST_STATE_NULL) { - GST_WARNING_OBJECT (camera, - "can't use set element until next video bin NULL to READY state change"); - } - gst_camerabin_video_set_video_enc (GST_CAMERABIN_VIDEO (camera->vidbin), - g_value_get_object (value)); - break; - case ARG_AUDIO_ENC: - if (GST_STATE (camera->vidbin) != GST_STATE_NULL) { - GST_WARNING_OBJECT (camera, - "can't use set element until next video bin NULL to READY state change"); - } - gst_camerabin_video_set_audio_enc (GST_CAMERABIN_VIDEO (camera->vidbin), - g_value_get_object (value)); - break; - case ARG_VIDEO_MUX: - if (GST_STATE (camera->vidbin) != GST_STATE_NULL) { - GST_WARNING_OBJECT (camera->vidbin, - "can't use set element until next video bin NULL to READY state change"); - } - gst_camerabin_video_set_muxer (GST_CAMERABIN_VIDEO (camera->vidbin), - g_value_get_object (value)); - break; - case ARG_IMAGE_POST: - if (GST_STATE (camera->imgbin) != GST_STATE_NULL) { - GST_WARNING_OBJECT (camera, - "can't use set element until next image bin NULL to READY state change"); - } - gst_camerabin_image_set_postproc (GST_CAMERABIN_IMAGE (camera->imgbin), - g_value_get_object (value)); - break; - case ARG_IMAGE_ENC: - if (GST_STATE (camera->imgbin) != GST_STATE_NULL) { - GST_WARNING_OBJECT (camera, - "can't use set element until next image bin NULL to READY state change"); - } - gst_camerabin_image_set_encoder (GST_CAMERABIN_IMAGE (camera->imgbin), - g_value_get_object (value)); - break; - case ARG_VF_SINK: - if (GST_STATE (camera) != GST_STATE_NULL) { - GST_ELEMENT_ERROR (camera, CORE, FAILED, - ("camerabin must be in NULL state when setting the view finder element"), - (NULL)); - } else { - if (camera->user_vf_sink) - gst_object_unref (camera->user_vf_sink); - camera->user_vf_sink = g_value_get_object (value); - gst_object_ref (camera->user_vf_sink); - } - break; - case ARG_VIDEO_SRC: - if (GST_STATE (camera) != GST_STATE_NULL) { - GST_ELEMENT_ERROR (camera, CORE, FAILED, - ("camerabin must be in NULL state when setting the video source element"), - (NULL)); - } else { - if (camera->user_vid_src) - gst_object_unref (camera->user_vid_src); - camera->user_vid_src = g_value_get_object (value); - gst_object_ref (camera->user_vid_src); - } - break; - case ARG_AUDIO_SRC: - if (GST_STATE (camera->vidbin) != GST_STATE_NULL) { - GST_WARNING_OBJECT (camera, - "can't use set element until next video bin NULL to READY state change"); - } - gst_camerabin_video_set_audio_src (GST_CAMERABIN_VIDEO (camera->vidbin), - g_value_get_object (value)); - break; - case ARG_FILTER_CAPS: - GST_OBJECT_LOCK (camera); - if (camera->view_finder_caps) { - gst_caps_unref (camera->view_finder_caps); - } - camera->view_finder_caps = gst_caps_copy (gst_value_get_caps (value)); - GST_OBJECT_UNLOCK (camera); - gst_camerabin_set_capsfilter_caps (camera, camera->view_finder_caps); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_camerabin_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstCameraBin *camera = GST_CAMERABIN (object); - - switch (prop_id) { - case ARG_FILENAME: - g_value_set_string (value, camera->filename->str); - break; - case ARG_MODE: - g_value_set_enum (value, camera->mode); - break; - case ARG_MUTE: - g_value_set_boolean (value, - gst_camerabin_video_get_mute (GST_CAMERABIN_VIDEO (camera->vidbin))); - break; - case ARG_ZOOM: - g_value_set_int (value, g_atomic_int_get (&camera->zoom)); - break; - case ARG_IMAGE_POST: - g_value_set_object (value, - gst_camerabin_image_get_postproc (GST_CAMERABIN_IMAGE - (camera->imgbin))); - break; - case ARG_IMAGE_ENC: - g_value_set_object (value, - gst_camerabin_image_get_encoder (GST_CAMERABIN_IMAGE - (camera->imgbin))); - break; - case ARG_VIDEO_POST: - g_value_set_object (value, - gst_camerabin_video_get_post (GST_CAMERABIN_VIDEO (camera->vidbin))); - break; - case ARG_VIDEO_ENC: - g_value_set_object (value, - gst_camerabin_video_get_video_enc (GST_CAMERABIN_VIDEO - (camera->vidbin))); - break; - case ARG_AUDIO_ENC: - g_value_set_object (value, - gst_camerabin_video_get_audio_enc (GST_CAMERABIN_VIDEO - (camera->vidbin))); - break; - case ARG_VIDEO_MUX: - g_value_set_object (value, - gst_camerabin_video_get_muxer (GST_CAMERABIN_VIDEO (camera->vidbin))); - break; - case ARG_VF_SINK: - g_value_set_object (value, camera->user_vf_sink); - break; - case ARG_VIDEO_SRC: - g_value_set_object (value, camera->src_vid_src); - break; - case ARG_AUDIO_SRC: - g_value_set_object (value, - gst_camerabin_video_get_audio_src (GST_CAMERABIN_VIDEO - (camera->vidbin))); - break; - case ARG_INPUT_CAPS: - gst_value_set_caps (value, gst_camerabin_get_allowed_input_caps (camera)); - break; - case ARG_FILTER_CAPS: - gst_value_set_caps (value, camera->view_finder_caps); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* - * GstElement functions implementation - */ - -static GstStateChangeReturn -gst_camerabin_change_state (GstElement * element, GstStateChange transition) -{ - GstCameraBin *camera = GST_CAMERABIN (element); - GstStateChangeReturn ret; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!camerabin_create_elements (camera)) { - ret = GST_STATE_CHANGE_FAILURE; - goto done; - } - /* Lock to control image and video bin state separately - from view finder */ - gst_element_set_locked_state (camera->imgbin, TRUE); - gst_element_set_locked_state (camera->vidbin, TRUE); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - camerabin_setup_src_elements (camera); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - /* If using autovideosink, set view finder sink properties - now that actual sink has been created. */ - camerabin_setup_view_elements (camera); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_element_set_locked_state (camera->imgbin, FALSE); - gst_element_set_locked_state (camera->vidbin, FALSE); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_LOG_OBJECT (camera, "PAUSED to READY"); - g_mutex_lock (camera->capture_mutex); - if (camera->capturing) { - GST_WARNING_OBJECT (camera, "was capturing when changing to READY"); - camera->capturing = FALSE; - /* Reset capture and don't wait for capturing to finish properly. - Proper capturing should have been finished before going to READY. */ - gst_camerabin_reset_to_view_finder (camera); - g_cond_signal (camera->cond); - } - g_mutex_unlock (camera->capture_mutex); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - camerabin_destroy_elements (camera); - break; - default: - break; - } - -done: - - return ret; -} - -/* - * GstBin functions implementation - */ - -/* Peek eos messages but don't interfere with bin msg handling */ -static void -gst_camerabin_handle_message_func (GstBin * bin, GstMessage * msg) -{ - GstCameraBin *camera = GST_CAMERABIN (bin); - - switch (GST_MESSAGE_TYPE (msg)) { - case GST_MESSAGE_EOS: - if (GST_MESSAGE_SRC (msg) == GST_OBJECT (camera->vidbin)) { - /* Video eos */ - GST_DEBUG_OBJECT (camera, - "got video eos message, stopping video capture"); - g_mutex_lock (camera->capture_mutex); - camera->capturing = FALSE; - g_cond_signal (camera->cond); - g_mutex_unlock (camera->capture_mutex); - } else if (GST_MESSAGE_SRC (msg) == GST_OBJECT (camera->imgbin)) { - /* Image eos */ - GST_DEBUG_OBJECT (camera, "got image eos message"); - /* Unblock pad to process next buffer */ - gst_pad_set_blocked_async (camera->pad_src_img, FALSE, - (GstPadBlockCallback) image_pad_blocked, camera); - } - break; - default: - break; - } - GST_BIN_CLASS (parent_class)->handle_message (bin, msg); -} - -/* - * Action signal function implementation - */ - -static void -gst_camerabin_user_start (GstCameraBin * camera) -{ - - GST_INFO_OBJECT (camera, "starting capture"); - if (camera->paused) { - gst_camerabin_user_pause (camera); - return; - } - - if (!camera->active_bin) { - GST_INFO_OBJECT (camera, "mode not explicitly set by application"); - gst_camerabin_change_mode (camera, camera->mode); - } - - if (g_str_equal (camera->filename->str, "")) { - GST_ELEMENT_ERROR (camera, CORE, FAILED, - ("set filename before starting capture"), (NULL)); - return; - } - - g_mutex_lock (camera->capture_mutex); - if (camera->capturing) { - GST_WARNING_OBJECT (camera, "capturing \"%s\" ongoing, set new filename", - camera->filename->str); - g_mutex_unlock (camera->capture_mutex); - return; - } - g_mutex_unlock (camera->capture_mutex); - - g_object_set (G_OBJECT (camera->active_bin), "filename", - camera->filename->str, NULL); - - if (camera->active_bin == camera->imgbin) { - gst_camerabin_start_image_capture (camera); - } else if (camera->active_bin == camera->vidbin) { - gst_camerabin_start_video_recording (camera); - } -} - -static void -gst_camerabin_user_stop (GstCameraBin * camera) -{ - GST_INFO_OBJECT (camera, "stopping %s capture", - camera->mode ? "video" : "image"); - gst_camerabin_do_stop (camera); - gst_camerabin_reset_to_view_finder (camera); -} - -static void -gst_camerabin_user_pause (GstCameraBin * camera) -{ - if (camera->active_bin == camera->vidbin) { - if (!camera->paused) { - GST_INFO_OBJECT (camera, "pausing capture"); - - /* Bring all camerabin elements to PAUSED */ - gst_element_set_locked_state (camera->vidbin, FALSE); - gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED); - - /* Switch to view finder mode */ - g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE, - "active-pad", camera->pad_src_view, NULL); - - /* Enable view finder mode in v4l2camsrc */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS - (camera->src_vid_src), "capture-mode")) { - g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 0, NULL); - } - - /* Set view finder to PLAYING and leave videobin PAUSED */ - gst_element_set_locked_state (camera->vidbin, TRUE); - gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING); - - camera->paused = TRUE; - } else { - GST_INFO_OBJECT (camera, "unpausing capture"); - - /* Bring all camerabin elements to PAUSED */ - gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED); - - /* Switch to video recording mode */ - g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", TRUE, - "active-pad", camera->pad_src_vid, NULL); - - /* Enable video recording mode in v4l2camsrc */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS - (camera->src_vid_src), "capture-mode")) { - g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 2, NULL); - } - - /* Bring all camerabin elements to PLAYING */ - gst_element_set_locked_state (camera->vidbin, FALSE); - gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING); - gst_element_set_locked_state (camera->vidbin, TRUE); - - camera->paused = FALSE; - } - GST_DEBUG_OBJECT (camera, "pause done"); - } else { - GST_WARNING ("pausing in image capture mode disabled"); - } -} - -static void -gst_camerabin_user_res_fps (GstCameraBin * camera, gint width, gint height, - gint fps_n, gint fps_d) -{ - GstState state; - - GST_INFO_OBJECT (camera, "switching resolution to %dx%d and fps to %d/%d", - width, height, fps_n, fps_d); - - state = GST_STATE (camera); - gst_element_set_state (GST_ELEMENT (camera), GST_STATE_READY); - camera->width = width; - camera->height = height; - camera->fps_n = fps_n; - camera->fps_d = fps_d; - gst_element_set_state (GST_ELEMENT (camera), state); -} - -static void -gst_camerabin_user_image_res (GstCameraBin * camera, gint width, gint height) -{ - GstStructure *structure; - GstCaps *new_caps = NULL; - guint32 format = 0; - - g_return_if_fail (camera != NULL); - - if (width && height && camera->view_finder_caps) { - /* Use view finder mode caps as a basis */ - structure = gst_caps_get_structure (camera->view_finder_caps, 0); - - /* Set new resolution for image capture */ - new_caps = gst_caps_new_simple (gst_structure_get_name (structure), - "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); - - /* Set format according to current videosrc format */ - format = get_srcpad_current_format (camera->src_vid_src); - if (format) { - gst_caps_set_simple (new_caps, "format", GST_TYPE_FOURCC, format, NULL); - } - - /* Set allowed framerate for the resolution. */ - gst_camerabin_set_allowed_framerate (camera, new_caps); - - /* Reset the format to match with view finder mode caps */ - if (gst_structure_get_fourcc (structure, "format", &format)) { - gst_caps_set_simple (new_caps, "format", GST_TYPE_FOURCC, format, NULL); - } - } - - GST_INFO_OBJECT (camera, - "init filter caps for image capture %" GST_PTR_FORMAT, new_caps); - gst_caps_replace (&camera->image_capture_caps, new_caps); -} - -/* entry point to initialize the plug-in - * initialize the plug-in itself - * register the element factories and pad templates - * register the features - */ -static gboolean -plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (gst_camerabin_debug, "camerabin", 0, "CameraBin"); - - return gst_element_register (plugin, "camerabin", - GST_RANK_NONE, GST_TYPE_CAMERABIN); -} - -/* this is the structure that gstreamer looks for to register plugins - */ -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "camerabin", - "High level api for DC (Digital Camera) application", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/gstcamerabin.h --- a/gst_plugins_good/gst/camerabin/gstcamerabin.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,171 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -#ifndef __GST_CAMERABIN_H__ -#define __GST_CAMERABIN_H__ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include - -#include "camerabinimage.h" -#include "camerabinvideo.h" - -G_BEGIN_DECLS - -/* #defines don't like whitespacey bits */ -#define GST_TYPE_CAMERABIN \ - (gst_camerabin_get_type()) -#define GST_CAMERABIN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAMERABIN,GstCameraBin)) -#define GST_CAMERABIN_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAMERABIN,GstCameraBinClass)) -#define GST_IS_CAMERABIN(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAMERABIN)) -#define GST_IS_CAMERABIN_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAMERABIN)) - -typedef struct _GstCameraBin GstCameraBin; -typedef struct _GstCameraBinClass GstCameraBinClass; - -/** - * GstCameraBin: - * - * The opaque #GstCameraBin structure. - */ - -struct _GstCameraBin -{ - GstPipeline parent; - - /* private */ - GString *filename; - gint mode; /* MODE_IMAGE or MODE_VIDEO */ - guint num_img_buffers; /* no of image buffers captured */ - gboolean stop_requested; /* TRUE if capturing stop needed */ - gboolean paused; /* TRUE if capturing paused */ - - /* resolution and frames per second of image captured by v4l2 device */ - gint width; - gint height; - gint fps_n; - gint fps_d; - - /* Caps applied to capsfilters when taking still image */ - GstCaps *image_capture_caps; - - /* Caps applied to capsfilters when in view finder mode */ - GstCaps *view_finder_caps; - - /* Caps that videosrc supports */ - GstCaps *allowed_caps; - - /* The digital zoom (from 100% to 1000%) */ - gint zoom; - - /* concurrency control */ - GMutex *capture_mutex; - GCond *cond; - gboolean capturing; - - /* pad names for output and input selectors */ - GstPad *pad_src_view; - GstPad *pad_view_src; - GstPad *pad_src_img; - GstPad *pad_view_img; - GstPad *pad_src_vid; - GstPad *pad_view_vid; - - GstPad *srcpad_zoom_filter; - - GstElement *imgbin; /* bin that holds image capturing elements */ - GstElement *vidbin; /* bin that holds video capturing elements */ - GstElement *active_bin; /* image or video bin that is currently in use */ - - /* source elements */ - GstElement *src_vid_src; - GstElement *src_filter; - GstElement *src_zoom_crop; - GstElement *src_zoom_scale; - GstElement *src_zoom_filter; - GstElement *src_out_sel; - - /* view finder elements */ - GstElement *view_in_sel; - GstElement *view_scale; - GstElement *view_sink; - - /* User configurable elements */ - GstElement *user_vid_src; - GstElement *user_vf_sink; - - /* Night mode handling */ - gboolean night_mode; - gint pre_night_fps_n; - gint pre_night_fps_d; -}; - -/** - * GstCameraBinClass: - * - * The #GstCameraBin class structure. - */ -struct _GstCameraBinClass -{ - GstPipelineClass parent_class; - - /* action signals */ - - void (*user_start) (GstCameraBin * camera); - void (*user_stop) (GstCameraBin * camera); - void (*user_pause) (GstCameraBin * camera); - void (*user_res_fps) (GstCameraBin * camera, gint width, gint height, - gint fps_n, gint fps_d); - void (*user_image_res) (GstCameraBin * camera, gint width, gint height); - - /* signals (callback) */ - - gboolean (*img_done) (GstCameraBin * camera, GString * filename); -}; - -/** - * GstCameraBinMode: - * @MODE_IMAGE: image capture - * @MODE_VIDEO: video capture - * - * Capture mode to use. - */ -typedef enum -{ - MODE_IMAGE = 0, - MODE_VIDEO -} GstCameraBinMode; - -#ifdef __SYMBIAN32__ -IMPORT_C -#endif -GType gst_camerabin_get_type (void); - -G_END_DECLS - -#endif /* #ifndef __GST_CAMERABIN_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/gstcamerabincolorbalance.c --- a/gst_plugins_good/gst/camerabin/gstcamerabincolorbalance.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -/* - * Includes - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gstcamerabincolorbalance.h" -#include "gstcamerabin.h" - -/* - * static functions implementation - */ - -static const GList * -gst_camerabin_color_balance_list_channels (GstColorBalance * cb) -{ - if (cb && GST_CAMERABIN (cb)->src_vid_src) { - GstColorBalance *cbl = GST_COLOR_BALANCE (GST_CAMERABIN (cb)->src_vid_src); - return gst_color_balance_list_channels (cbl); - } else { - return NULL; - } -} - -static void -gst_camerabin_color_balance_set_value (GstColorBalance * cb, - GstColorBalanceChannel * channel, gint value) -{ - if (cb && GST_CAMERABIN (cb)->src_vid_src) { - GstColorBalance *cbl = GST_COLOR_BALANCE (GST_CAMERABIN (cb)->src_vid_src); - gst_color_balance_set_value (cbl, channel, value); - } -} - -static gint -gst_camerabin_color_balance_get_value (GstColorBalance * cb, - GstColorBalanceChannel * channel) -{ - if (cb && GST_CAMERABIN (cb)->src_vid_src) { - GstColorBalance *cbl = GST_COLOR_BALANCE (GST_CAMERABIN (cb)->src_vid_src); - return gst_color_balance_get_value (cbl, channel); - } else { - return 0; - } -} - -/* - * extern functions implementation - */ - -void -gst_camerabin_color_balance_init (GstColorBalanceClass * iface) -{ - /* FIXME: to get the same type as v4l2src */ - GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE; - iface->list_channels = gst_camerabin_color_balance_list_channels; - iface->set_value = gst_camerabin_color_balance_set_value; - iface->get_value = gst_camerabin_color_balance_get_value; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/gstcamerabincolorbalance.h --- a/gst_plugins_good/gst/camerabin/gstcamerabincolorbalance.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -#ifndef __GST_CAMERA_COLOR_BALANCE_H__ -#define __GST_CAMERA_COLOR_BALANCE_H__ - -#include - -extern void gst_camerabin_color_balance_init (GstColorBalanceClass * iface); - -#endif /* #ifndef __GST_CAMERA_COLOR_BALANCE_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/gstcamerabinphotography.c --- a/gst_plugins_good/gst/camerabin/gstcamerabinphotography.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * Photography interface implementation for camerabin. - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gstcamerabinphotography.h" -#include "gstcamerabin.h" - -GST_DEBUG_CATEGORY_STATIC (camerabinphoto_debug); -#define GST_CAT_DEFAULT camerabinphoto_debug - -#define PHOTOGRAPHY_IS_OK(photo_elem) (GST_IS_ELEMENT (photo_elem) && \ - gst_element_implements_interface (photo_elem, GST_TYPE_PHOTOGRAPHY)) - -#define GST_PHOTOGRAPHY_IMPL_TEMPLATE(function_name, param_type) \ -static gboolean \ -gst_camerabin_set_ ## function_name (GstPhotography *photo, param_type param) \ -{ \ - GstCameraBin *camera; \ - gboolean ret = FALSE; \ - g_return_val_if_fail (photo != NULL, FALSE); \ - camera = GST_CAMERABIN (photo); \ - if (PHOTOGRAPHY_IS_OK (camera->src_vid_src)) { \ - ret = gst_photography_set_ ## function_name (GST_PHOTOGRAPHY (camera->src_vid_src), param); \ - } \ - return ret; \ -} \ -static gboolean \ -gst_camerabin_get_ ## function_name (GstPhotography *photo, param_type * param) \ -{ \ - GstCameraBin *camera; \ - gboolean ret = FALSE; \ - g_return_val_if_fail (photo != NULL, FALSE); \ - camera = GST_CAMERABIN (photo); \ - if (PHOTOGRAPHY_IS_OK (camera->src_vid_src)) { \ - ret = gst_photography_get_ ## function_name (GST_PHOTOGRAPHY (camera->src_vid_src), param); \ - } \ - return ret; \ -} - -GST_PHOTOGRAPHY_IMPL_TEMPLATE (ev_compensation, gfloat); -GST_PHOTOGRAPHY_IMPL_TEMPLATE (iso_speed, guint); -GST_PHOTOGRAPHY_IMPL_TEMPLATE (white_balance_mode, GstWhiteBalanceMode); -GST_PHOTOGRAPHY_IMPL_TEMPLATE (colour_tone_mode, GstColourToneMode); -GST_PHOTOGRAPHY_IMPL_TEMPLATE (flash_mode, GstFlashMode); - -static gboolean -gst_camerabin_set_zoom (GstPhotography * photo, gfloat zoom) -{ - GstCameraBin *camera; - - g_return_val_if_fail (photo != NULL, FALSE); - - camera = GST_CAMERABIN (photo); - - /* camerabin can zoom by itself */ - g_object_set (camera, "zoom", (gint) (CLAMP (zoom, 1.0, 10.0) * 100), NULL); - - return TRUE; -} - -static gboolean -gst_camerabin_get_zoom (GstPhotography * photo, gfloat * zoom) -{ - GstCameraBin *camera; - gint cb_zoom = 0; - - g_return_val_if_fail (photo != NULL, FALSE); - - camera = GST_CAMERABIN (photo); - - g_object_get (camera, "zoom", &cb_zoom, NULL); - *zoom = (gfloat) (cb_zoom / 100.0); - - return TRUE; -} - -static gboolean -gst_camerabin_set_scene_mode (GstPhotography * photo, GstSceneMode scene_mode) -{ - GstCameraBin *camera; - gboolean ret = FALSE; - - g_return_val_if_fail (photo != NULL, FALSE); - - camera = GST_CAMERABIN (photo); - - if (scene_mode == GST_PHOTOGRAPHY_SCENE_MODE_NIGHT) { - GST_DEBUG ("enabling night mode, lowering fps"); - /* Make camerabin select the lowest allowed frame rate */ - camera->night_mode = TRUE; - /* Remember frame rate before setting night mode */ - camera->pre_night_fps_n = camera->fps_n; - camera->pre_night_fps_d = camera->fps_d; - g_signal_emit_by_name (camera, "user-res-fps", camera->width, - camera->height, 0, 0, 0); - } else { - if (camera->night_mode) { - GST_DEBUG ("disabling night mode, restoring fps to %d/%d", - camera->pre_night_fps_n, camera->pre_night_fps_d); - camera->night_mode = FALSE; - g_signal_emit_by_name (camera, "user-res-fps", camera->width, - camera->height, camera->pre_night_fps_n, camera->pre_night_fps_d, 0); - } - } - - if (PHOTOGRAPHY_IS_OK (camera->src_vid_src)) { - ret = gst_photography_set_scene_mode (GST_PHOTOGRAPHY (camera->src_vid_src), - scene_mode); - } - return ret; -} - -static gboolean -gst_camerabin_get_scene_mode (GstPhotography * photo, GstSceneMode * scene_mode) -{ - GstCameraBin *camera; - gboolean ret = FALSE; - - g_return_val_if_fail (photo != NULL, FALSE); - - camera = GST_CAMERABIN (photo); - - if (PHOTOGRAPHY_IS_OK (camera->src_vid_src)) { - ret = gst_photography_get_scene_mode (GST_PHOTOGRAPHY (camera->src_vid_src), - scene_mode); - } - return ret; -} - -static GstPhotoCaps -gst_camerabin_get_capabilities (GstPhotography * photo) -{ - GstCameraBin *camera; - /* camerabin can zoom by itself */ - GstPhotoCaps pcaps = GST_PHOTOGRAPHY_CAPS_ZOOM; - - g_return_val_if_fail (photo != NULL, FALSE); - - camera = GST_CAMERABIN (photo); - - if (GST_IS_ELEMENT (camera->src_vid_src) && - gst_element_implements_interface (camera->src_vid_src, - GST_TYPE_PHOTOGRAPHY)) { - GstPhotography *p2 = GST_PHOTOGRAPHY (camera->src_vid_src); - pcaps |= gst_photography_get_capabilities (p2); - } - - return pcaps; -} - -static void -gst_camerabin_set_autofocus (GstPhotography * photo, gboolean on) -{ - GstCameraBin *camera; - - g_return_if_fail (photo != NULL); - - camera = GST_CAMERABIN (photo); - - GST_DEBUG_OBJECT (camera, "setting autofocus %s", on ? "ON" : "OFF"); - - if (PHOTOGRAPHY_IS_OK (camera->src_vid_src)) { - gst_photography_set_autofocus (GST_PHOTOGRAPHY (camera->src_vid_src), on); - } -} - - -void -gst_camerabin_photography_init (GstPhotographyInterface * iface) -{ - GST_DEBUG_CATEGORY_INIT (camerabinphoto_debug, "camerabinphoto", 0, - "Camerabin photography interface debugging"); - - GST_INFO ("initing"); - - iface->set_ev_compensation = gst_camerabin_set_ev_compensation; - iface->get_ev_compensation = gst_camerabin_get_ev_compensation; - - iface->set_iso_speed = gst_camerabin_set_iso_speed; - iface->get_iso_speed = gst_camerabin_get_iso_speed; - - iface->set_white_balance_mode = gst_camerabin_set_white_balance_mode; - iface->get_white_balance_mode = gst_camerabin_get_white_balance_mode; - - iface->set_colour_tone_mode = gst_camerabin_set_colour_tone_mode; - iface->get_colour_tone_mode = gst_camerabin_get_colour_tone_mode; - - iface->set_scene_mode = gst_camerabin_set_scene_mode; - iface->get_scene_mode = gst_camerabin_get_scene_mode; - - iface->set_flash_mode = gst_camerabin_set_flash_mode; - iface->get_flash_mode = gst_camerabin_get_flash_mode; - - iface->set_zoom = gst_camerabin_set_zoom; - iface->get_zoom = gst_camerabin_get_zoom; - - iface->get_capabilities = gst_camerabin_get_capabilities; - - iface->set_autofocus = gst_camerabin_set_autofocus; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/gstcamerabinphotography.h --- a/gst_plugins_good/gst/camerabin/gstcamerabinphotography.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * Photography interface implementation for camerabin - * - * 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. - */ - -#ifndef __GST_CAMERABIN_PHOTOGRAPHY_H__ -#define __GST_CAMERABIN_PHOTOGRAPHY_H__ - -#include - -void gst_camerabin_photography_init (GstPhotographyInterface * iface); - -#endif /* #ifndef __GST_CAMERABIN_PHOTOGRAPHY_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/gstcamerabinxoverlay.c --- a/gst_plugins_good/gst/camerabin/gstcamerabinxoverlay.c Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -/* - * Includes - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gstcamerabinxoverlay.h" -#include "gstcamerabin.h" - -/* - * static functions implementation - */ - -static void -gst_camerabin_expose (GstXOverlay * overlay) -{ - if (overlay && GST_CAMERABIN (overlay)->view_sink) { - GstXOverlay *xoverlay = GST_X_OVERLAY (GST_CAMERABIN (overlay)->view_sink); - gst_x_overlay_expose (xoverlay); - } -} - -static void -gst_camerabin_set_xwindow_id (GstXOverlay * overlay, gulong xwindow_id) -{ - if (overlay && GST_CAMERABIN (overlay)->view_sink) { - GstXOverlay *xoverlay = GST_X_OVERLAY (GST_CAMERABIN (overlay)->view_sink); - gst_x_overlay_set_xwindow_id (xoverlay, xwindow_id); - } -} - -static void -gst_camerabin_set_event_handling (GstXOverlay * overlay, gboolean handle_events) -{ - if (overlay && GST_CAMERABIN (overlay)->view_sink) { - GstXOverlay *xoverlay = GST_X_OVERLAY (GST_CAMERABIN (overlay)->view_sink); - gst_x_overlay_handle_events (xoverlay, handle_events); - } -} - -/* - * extern functions implementation - */ - -void -gst_camerabin_xoverlay_init (GstXOverlayClass * iface) -{ - iface->set_xwindow_id = gst_camerabin_set_xwindow_id; - iface->expose = gst_camerabin_expose; - iface->handle_events = gst_camerabin_set_event_handling; -} diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_good/gst/camerabin/gstcamerabinxoverlay.h --- a/gst_plugins_good/gst/camerabin/gstcamerabinxoverlay.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -#ifndef __GST_CAMERAXOVERLAY_H__ -#define __GST_CAMERAXOVERLAY_H__ - -#include - -extern void gst_camerabin_xoverlay_init (GstXOverlayClass * iface); - -#endif /* #ifndef __GST_CAMERAXOVERLAY_H__ */ diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_symbian/gst/devsound/gstdevsoundsrc.c --- a/gst_plugins_symbian/gst/devsound/gstdevsoundsrc.c Fri May 28 18:11:17 2010 -0500 +++ b/gst_plugins_symbian/gst/devsound/gstdevsoundsrc.c Fri Jun 25 17:18:46 2010 -0500 @@ -394,7 +394,7 @@ devsoundsrc->handle=NULL; devsoundsrc->preference = 0; //default=>EMdaPriorityPreferenceNone; devsoundsrc->priority = 0; //default=>EMdaPriorityNormal; - devsoundsrc->firstimecreatecalled = 0; + devsoundsrc->firstTimeInit = kUnInitialized; // pthread_mutex_init(&create_mutex1, NULL); // pthread_cond_init(&create_condition1, NULL); //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "gst_devsound_src_init EXIT ",NULL); @@ -500,7 +500,6 @@ pthread_mutex_unlock(&(create_mutex1)); // TODO obtain mutex here consumer_thread_state = CONSUMER_THREAD_UNINITIALIZED; - devsoundsrc->firstimecreatecalled = 0; pthread_exit(NULL); } break; @@ -772,6 +771,7 @@ g_free(src->device); src->device = NULL; + src->firstTimeInit = kUnInitialized; //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "gst_devsound_src_stop EXIT "); return TRUE; } @@ -882,8 +882,14 @@ GST_OBJECT_UNLOCK(dsrc); //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "AFTER POP in CREATE ",NULL); if(!popBuffer) - { - return GST_FLOW_UNEXPECTED; + { + return GST_FLOW_UNEXPECTED; + } + if(dsrc->firstTimeInit != kPlayed) + { + dsrc->prevbuffersize = gst_base_src_get_blocksize(src); + gst_base_src_set_blocksize (src, GST_BUFFER_SIZE(popBuffer)); + (*buf)->size = GST_BUFFER_SIZE(popBuffer); } // copy the data from the popped buffer based on how much of the incoming //buffer size is left to fill. we might have filled the fresh buffer somewhat @@ -914,12 +920,19 @@ popBuffer = NULL; } } - if( dsrc->firstimecreatecalled < 2 ) - {/// nitin changes - ++dsrc->firstimecreatecalled; - return GST_FLOW_OK; + if (dsrc->firstTimeInit == kPlayBufferPreRoll) + { + gst_base_src_set_blocksize (src, dsrc->prevbuffersize); + dsrc->firstTimeInit = kPlayed; + return GST_FLOW_OK; } - } + + if (dsrc->firstTimeInit == kPausedToPlaying) + { + dsrc->firstTimeInit = kPlayBufferPreRoll; + return GST_FLOW_OK; + } + } //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "gst_devsound_src_create EXIT ",NULL); return GST_FLOW_OK; } @@ -930,10 +943,12 @@ { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstDevsoundSrc *src= GST_DEVSOUND_SRC (element); - + switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + if (src->firstTimeInit != kPlayed) + src->firstTimeInit = kPausedToPlaying; if(cmd == PAUSE) { cmd = RESUME; diff -r 5cb7d96a6887 -r 8d4f92b9230e gst_plugins_symbian/gst/devsound/gstdevsoundsrc.h --- a/gst_plugins_symbian/gst/devsound/gstdevsoundsrc.h Fri May 28 18:11:17 2010 -0500 +++ b/gst_plugins_symbian/gst/devsound/gstdevsoundsrc.h Fri Jun 25 17:18:46 2010 -0500 @@ -54,6 +54,13 @@ gboolean priorityupdate; }; +typedef enum +{ + kUnInitialized = -1, + kPausedToPlaying, + kPlayBufferPreRoll, + kPlayed +} ; struct _GstDevsoundSrc { GstPushSrc src; @@ -86,8 +93,8 @@ gboolean g729vadmode; gint ilbcencodemode; gboolean ilbcvadmode; - gint firstimecreatecalled; - + gint firstTimeInit; + guint prevbuffersize; }; diff -r 5cb7d96a6887 -r 8d4f92b9230e gstreamer_core/group/bld.inf --- a/gstreamer_core/group/bld.inf Fri May 28 18:11:17 2010 -0500 +++ b/gstreamer_core/group/bld.inf Fri Jun 25 17:18:46 2010 -0500 @@ -25,93 +25,93 @@ DEFAULT PRJ_EXPORTS -../gst/glib-compat.h /epoc32/include/platform/mw/gstreamer/gst/glib-compat.h -../gst/gstbin.h /epoc32/include/platform/mw/gstreamer/gst/gstbin.h -../gst/gstbuffer.h /epoc32/include/platform/mw/gstreamer/gst/gstbuffer.h -../gst/gstbus.h /epoc32/include/platform/mw/gstreamer/gst/gstbus.h -../gst/gstcaps.h /epoc32/include/platform/mw/gstreamer/gst/gstcaps.h -../gst/gstchildproxy.h /epoc32/include/platform/mw/gstreamer/gst/gstchildproxy.h -../gst/gstclock.h /epoc32/include/platform/mw/gstreamer/gst/gstclock.h -../gst/gstcompat.h /epoc32/include/platform/mw/gstreamer/gst/gstcompat.h -../gst/gstconfig.h /epoc32/include/platform/mw/gstreamer/gst/gstconfig.h -../gst/gstelementfactory.h /epoc32/include/platform/mw/gstreamer/gst/gstelementfactory.h -../gst/gstelement.h /epoc32/include/platform/mw/gstreamer/gst/gstelement.h -../gst/gstenumtypes.h /epoc32/include/platform/mw/gstreamer/gst/gstenumtypes.h -../gst/gsterror.h /epoc32/include/platform/mw/gstreamer/gst/gsterror.h -../gst/gstevent.h /epoc32/include/platform/mw/gstreamer/gst/gstevent.h -../gst/gstfilter.h /epoc32/include/platform/mw/gstreamer/gst/gstfilter.h -../gst/gstformat.h /epoc32/include/platform/mw/gstreamer/gst/gstformat.h -../gst/gstghostpad.h /epoc32/include/platform/mw/gstreamer/gst/gstghostpad.h -../gst/gst.h /epoc32/include/platform/mw/gstreamer/gst/gst.h -../gst/gstindexfactory.h /epoc32/include/platform/mw/gstreamer/gst/gstindexfactory.h -../gst/gstindex.h /epoc32/include/platform/mw/gstreamer/gst/gstindex.h -//../gst/gst_private.h /epoc32/include/platform/mw/gstreamer/gst/gst_private.h -//../gst/gst-i18n-lib.h /epoc32/include/platform/mw/gstreamer/gst/gst-i18n-lib.h -../gst/gstinfo.h /epoc32/include/platform/mw/gstreamer/gst/gstinfo.h -../gst/gstinterface.h /epoc32/include/platform/mw/gstreamer/gst/gstinterface.h -../gst/gstiterator.h /epoc32/include/platform/mw/gstreamer/gst/gstiterator.h -../gst/gstmacros.h /epoc32/include/platform/mw/gstreamer/gst/gstmacros.h -../gst/gstmarshal.h /epoc32/include/platform/mw/gstreamer/gst/gstmarshal.h -../gst/gstmessage.h /epoc32/include/platform/mw/gstreamer/gst/gstmessage.h -../gst/gstminiobject.h /epoc32/include/platform/mw/gstreamer/gst/gstminiobject.h -../gst/gstobject.h /epoc32/include/platform/mw/gstreamer/gst/gstobject.h -../gst/gstpad.h /epoc32/include/platform/mw/gstreamer/gst/gstpad.h -../gst/gstpadtemplate.h /epoc32/include/platform/mw/gstreamer/gst/gstpadtemplate.h -../gst/gstparse.h /epoc32/include/platform/mw/gstreamer/gst/gstparse.h -../gst/gstpipeline.h /epoc32/include/platform/mw/gstreamer/gst/gstpipeline.h -../gst/gstpluginfeature.h /epoc32/include/platform/mw/gstreamer/gst/gstpluginfeature.h -../gst/gstplugin.h /epoc32/include/platform/mw/gstreamer/gst/gstplugin.h -../gst/gstquery.h /epoc32/include/platform/mw/gstreamer/gst/gstquery.h -../gst/gstregistry.h /epoc32/include/platform/mw/gstreamer/gst/gstregistry.h -../gst/gstsegment.h /epoc32/include/platform/mw/gstreamer/gst/gstsegment.h -../gst/gststructure.h /epoc32/include/platform/mw/gstreamer/gst/gststructure.h -../gst/gstsystemclock.h /epoc32/include/platform/mw/gstreamer/gst/gstsystemclock.h -../gst/gsttaglist.h /epoc32/include/platform/mw/gstreamer/gst/gsttaglist.h -../gst/gsttagsetter.h /epoc32/include/platform/mw/gstreamer/gst/gsttagsetter.h -../gst/gsttask.h /epoc32/include/platform/mw/gstreamer/gst/gsttask.h -../gst/gsttrace.h /epoc32/include/platform/mw/gstreamer/gst/gsttrace.h -../gst/gsttypefindfactory.h /epoc32/include/platform/mw/gstreamer/gst/gsttypefindfactory.h -../gst/gsttypefind.h /epoc32/include/platform/mw/gstreamer/gst/gsttypefind.h -../gst/gsturi.h /epoc32/include/platform/mw/gstreamer/gst/gsturi.h -../gst/gstutils.h /epoc32/include/platform/mw/gstreamer/gst/gstutils.h -../gst/gstvalue.h /epoc32/include/platform/mw/gstreamer/gst/gstvalue.h -../gst/gstversion.h /epoc32/include/platform/mw/gstreamer/gst/gstversion.h -../gst/gstxml.h /epoc32/include/platform/mw/gstreamer/gst/gstxml.h -../gst/gst_global.h /epoc32/include/platform/mw/gstreamer/gst/gst_global.h +../gst/glib-compat.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/glib-compat.h) +../gst/gstbin.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstbin.h) +../gst/gstbuffer.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstbuffer.h) +../gst/gstbus.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstbus.h) +../gst/gstcaps.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstcaps.h) +../gst/gstchildproxy.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstchildproxy.h) +../gst/gstclock.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstclock.h) +../gst/gstcompat.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstcompat.h) +../gst/gstconfig.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstconfig.h) +../gst/gstelementfactory.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstelementfactory.h) +../gst/gstelement.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstelement.h) +../gst/gstenumtypes.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstenumtypes.h ) +../gst/gsterror.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gsterror.h ) +../gst/gstevent.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstevent.h ) +../gst/gstfilter.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstfilter.h ) +../gst/gstformat.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstformat.h ) +../gst/gstghostpad.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstghostpad.h ) +../gst/gst.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gst.h ) +../gst/gstindexfactory.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstindexfactory.h ) +../gst/gstindex.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstindex.h ) +//../gst/gst_private.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gst_private.h ) +//../gst/gst-i18n-lib.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gst-i18n-lib.h ) +../gst/gstinfo.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstinfo.h ) +../gst/gstinterface.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstinterface.h ) +../gst/gstiterator.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstiterator.h ) +../gst/gstmacros.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstmacros.h ) +../gst/gstmarshal.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstmarshal.h ) +../gst/gstmessage.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstmessage.h ) +../gst/gstminiobject.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstminiobject.h ) +../gst/gstobject.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstobject.h ) +../gst/gstpad.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstpad.h ) +../gst/gstpadtemplate.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstpadtemplate.h ) +../gst/gstparse.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstparse.h ) +../gst/gstpipeline.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstpipeline.h ) +../gst/gstpluginfeature.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstpluginfeature.h ) +../gst/gstplugin.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstplugin.h ) +../gst/gstquery.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstquery.h ) +../gst/gstregistry.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstregistry.h ) +../gst/gstsegment.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstsegment.h ) +../gst/gststructure.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gststructure.h ) +../gst/gstsystemclock.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstsystemclock.h ) +../gst/gsttaglist.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gsttaglist.h ) +../gst/gsttagsetter.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gsttagsetter.h ) +../gst/gsttask.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gsttask.h ) +../gst/gsttrace.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gsttrace.h ) +../gst/gsttypefindfactory.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gsttypefindfactory.h ) +../gst/gsttypefind.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gsttypefind.h ) +../gst/gsturi.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gsturi.h ) +../gst/gstutils.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstutils.h ) +../gst/gstvalue.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstvalue.h ) +../gst/gstversion.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstversion.h ) +../gst/gstxml.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstxml.h ) +../gst/gst_global.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gst_global.h ) -../gst/gstdebugutils.h /epoc32/include/platform/mw/gstreamer/gst/gstdebugutils.h -../gst/gstparamspecs.h /epoc32/include/platform/mw/gstreamer/gst/gstparamspecs.h -../gst/gstpoll.h /epoc32/include/platform/mw/gstreamer/gst/gstpoll.h -../gst/gstregistrybinary.h /epoc32/include/platform/mw/gstreamer/gst/gstregistrybinary.h -../gst/gstpreset.h /epoc32/include/platform/mw/gstreamer/gst/gstpreset.h -../gst/gstbufferlist.h /epoc32/include/platform/mw/gstreamer/gst/gstbufferlist.h -../gst/gsttaskpool.h /epoc32/include/platform/mw/gstreamer/gst/gsttaskpool.h +../gst/gstdebugutils.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstdebugutils.h ) +../gst/gstparamspecs.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstparamspecs.h ) +../gst/gstpoll.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstpoll.h ) +../gst/gstregistrybinary.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstregistrybinary.h ) +../gst/gstpreset.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstpreset.h ) +../gst/gstbufferlist.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gstbufferlist.h ) +../gst/gsttaskpool.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/gsttaskpool.h ) //libs //base -../libs/gst/base/gstadapter.h /epoc32/include/platform/mw/gstreamer/gst/base/gstadapter.h -../libs/gst/base/gstbasesink.h /epoc32/include/platform/mw/gstreamer/gst/base/gstbasesink.h -../libs/gst/base/gstbasesrc.h /epoc32/include/platform/mw/gstreamer/gst/base/gstbasesrc.h -../libs/gst/base/gstbasetransform.h /epoc32/include/platform/mw/gstreamer/gst/base/gstbasetransform.h -../libs/gst/base/gstcollectpads.h /epoc32/include/platform/mw/gstreamer/gst/base/gstcollectpads.h -../libs/gst/base/gstpushsrc.h /epoc32/include/platform/mw/gstreamer/gst/base/gstpushsrc.h -../libs/gst/base/gsttypefindhelper.h /epoc32/include/platform/mw/gstreamer/gst/base/gsttypefindhelper.h -../libs/gst/base/gstdataqueue.h /epoc32/include/platform/mw/gstreamer/gst/base/gstdataqueue.h +../libs/gst/base/gstadapter.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/base/gstadapter.h ) +../libs/gst/base/gstbasesink.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/base/gstbasesink.h ) +../libs/gst/base/gstbasesrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/base/gstbasesrc.h ) +../libs/gst/base/gstbasetransform.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/base/gstbasetransform.h ) +../libs/gst/base/gstcollectpads.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/base/gstcollectpads.h ) +../libs/gst/base/gstpushsrc.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/base/gstpushsrc.h ) +../libs/gst/base/gsttypefindhelper.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/base/gsttypefindhelper.h ) +../libs/gst/base/gstdataqueue.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/base/gstdataqueue.h ) //controller rj -../libs/gst/controller/gstcontroller.h /epoc32/include/platform/mw/gstreamer/gst/controller/gstcontroller.h -../libs/gst/controller/gstcontrolsource.h /epoc32/include/platform/mw/gstreamer/gst/controller/gstcontrolsource.h -../libs/gst/controller/gstinterpolationcontrolsource.h /epoc32/include/platform/mw/gstreamer/gst/controller/gstinterpolationcontrolsource.h +../libs/gst/controller/gstcontroller.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/controller/gstcontroller.h ) +../libs/gst/controller/gstcontrolsource.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/controller/gstcontrolsource.h ) +../libs/gst/controller/gstinterpolationcontrolsource.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/controller/gstinterpolationcontrolsource.h ) //dataprotocol -../libs/gst/dataprotocol/dataprotocol.h /epoc32/include/platform/mw/gstreamer/gst/dataprotocol/dataprotocol.h +../libs/gst/dataprotocol/dataprotocol.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/dataprotocol/dataprotocol.h ) //net -../libs/gst/net/gstnetclientclock.h /epoc32/include/platform/mw/gstreamer/gst/net/gstnetclientclock.h -../libs/gst/net/gstnet.h /epoc32/include/platform/mw/gstreamer/gst/net/gstnet.h -../libs/gst/net/gstnettimepacket.h /epoc32/include/platform/mw/gstreamer/gst/net/gstnettimepacket.h -../libs/gst/net/gstnettimeprovider.h /epoc32/include/platform/mw/gstreamer/gst/net/gstnettimeprovider.h +../libs/gst/net/gstnetclientclock.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/net/gstnetclientclock.h ) +../libs/gst/net/gstnet.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/net/gstnet.h ) +../libs/gst/net/gstnettimepacket.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/net/gstnettimepacket.h ) +../libs/gst/net/gstnettimeprovider.h MW_LAYER_PLATFORM_EXPORT_PATH(gstreamer/gst/net/gstnettimeprovider.h ) diff -r 5cb7d96a6887 -r 8d4f92b9230e internal/gstplayer/data/gstplayer.rss --- a/internal/gstplayer/data/gstplayer.rss Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,350 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library 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 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ -/* -* ============================================================================== -* Name : GSTPlayer.rss -* Part of : GSTPlayer -* Interface : -* Description : -* Version : -* - -* ============================================================================== -*/ - -// RESOURCE IDENTIFIER -NAME HEWB // 4 letter ID - - -// INCLUDES -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "GSTPlayer.hrh" -#include "GSTPlayer.rls" - -#define KWidth 176 -#define KHeight 100 -#define KMaxLength 256 - -// RESOURCE DEFINITIONS -// ----------------------------------------------------------------------------- -// -// Define the resource file signature -// This resource should be empty. -// -// ----------------------------------------------------------------------------- -// -RESOURCE RSS_SIGNATURE - { - } - -// ----------------------------------------------------------------------------- -// -// Default Document Name -// -// ----------------------------------------------------------------------------- -// -RESOURCE TBUF r_default_document_name - { - buf="HEWB"; - } - -// ----------------------------------------------------------------------------- -// -// Define default menu and CBA key. -// -// ----------------------------------------------------------------------------- -// -RESOURCE EIK_APP_INFO - { - menubar = r_gstplayer_menubar; - cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT; - } - - -// ----------------------------------------------------------------------------- -// -// r_helloworldbasic_menubar -// Menubar for HelloWorldBasic example -// -// ----------------------------------------------------------------------------- -// -RESOURCE MENU_BAR r_gstplayer_menubar - { - titles = - { - MENU_TITLE { menu_pane = r_gstplayer_menu; } - }; - } - -RESOURCE MENU_PANE r_play_cmd - { - items= - { - MENU_ITEM{command = EGSTPlayerNewSong;txt = "New Song";}, - MENU_ITEM{command = EGSTPlayerPlay;txt = "Play";}, - MENU_ITEM{command = EGSTPlayerSamplesPlayed; txt = "Samples Played"; }, - MENU_ITEM{command = EGSTPlayerSkPadCaps;txt = "Sink Pad Caps";cascade=r_sinkpad_caps;}, - MENU_ITEM{command = EGSTPlayerVolume;txt = "Volume"; cascade=r_volume_cmds;} - }; - } - -RESOURCE MENU_PANE r_record_cmd - { - items= - { - MENU_ITEM{command = EGSTPlayerRecordWav;txt = "Record WAV";}, - MENU_ITEM{command = EGSTPlayerRecordAac;txt = "Record AAC";}, - MENU_ITEM{command = EGSTPlayerRecordRaw;txt = "Record RAW";}, - MENU_ITEM{command = EGSTPlayerRecordAmr;txt = "Record AMR";}, - MENU_ITEM{command = EGSTPlayerRecordG711;txt = "Record G711";}, - MENU_ITEM{command = EGSTPlayerRecordG729;txt = "Record G729";}, - MENU_ITEM{command = EGSTPlayerRecordIlbc;txt = "Record ILBC";}, - MENU_ITEM { command = EGSTPlayerSamplesRecorded; txt = "Samples Recorded"; }, - MENU_ITEM{command = EGSTPlayerSourcePadCaps;txt = "Source Pad Caps";cascade=r_srcpad_caps;}, - MENU_ITEM{command = EGSTPlayerGain;txt = "Gain"; cascade=r_gain_cmds;} - }; - } - -RESOURCE MENU_PANE r_volume_cmds - { - items= - { - MENU_ITEM { command = EGSTPlayerCurrentVolume; txt = "Current Volume"; }, - MENU_ITEM { command = EGSTPlayerMaxVolume; txt = "Max Volume"; }, - MENU_ITEM { command = EGSTPlayerVolumeUp; txt = "Volume up"; }, - MENU_ITEM { command = EGSTPlayerVolumeDown; txt = "Volume down"; }, - MENU_ITEM { command = EGSTPlayerRightBalance; txt = "Right Balance"; }, - MENU_ITEM { command = EGSTPlayerLeftBalance; txt = "Left Balance"; } - }; - } - -RESOURCE MENU_PANE r_gain_cmds - { - items= - { - MENU_ITEM { command = EGSTPlayerCurrentGain; txt = "Current Gain"; }, - MENU_ITEM { command = EGSTPlayerMaxGain; txt = "Max Gain"; }, - MENU_ITEM { command = EGSTPlayerGainUp; txt = "Gain up"; }, - MENU_ITEM { command = EGSTPlayerGainDown; txt = "Gain down"; } - // MENU_ITEM { command = EGSTPlayerRightBalance; txt = "Right Balance"; }, - // MENU_ITEM { command = EGSTPlayerLeftBalance; txt = "Left Balance"; } - }; - } -RESOURCE MENU_PANE r_sinkpad_caps - { - items= - { - MENU_ITEM { command = EGSTPlayerSinkPadCaps; txt = "DevSound sinkpad caps"; }, - MENU_ITEM { command = EGSTPlayerNegotiatedSinkCaps; txt = "Negotiated Sink Caps"; } - }; - } - -RESOURCE MENU_PANE r_srcpad_caps - { - items= - { - MENU_ITEM { command = EGSTPlayerSrcPadCaps; txt = "DevSound srcpad caps"; }, - MENU_ITEM { command = EGSTPlayerNegotiatedSrcCaps; txt = "Negotiated Src Caps"; } - }; - } - -RESOURCE MENU_PANE r_sample_info - { - items= - { - MENU_ITEM { command = EGSTPlayerSamplesPlayed; txt = "Samples Played"; }, - MENU_ITEM { command = EGSTPlayerSamplesRecorded; txt = "Samples Recorded"; }//, - //MENU_ITEM { command = EGSTPlayerTimePlayed; txt = "Time Played"; } - }; - } - -// ----------------------------------------------------------------------------- -// -// r_helloworldbasic_menu -// Menu for "Options" -// -// ----------------------------------------------------------------------------- -// -RESOURCE MENU_PANE r_gstplayer_menu - { - items = - { - // added the new Options menu command here - MENU_ITEM - { - command = EGSTPlayerPlayerTest; - txt = "Play"; - cascade=r_play_cmd; - }, - MENU_ITEM - { - command = EGSTPlayerRecordTest; - txt = "Record"; - cascade=r_record_cmd; - }, - MENU_ITEM - { - command = EGSTPlayerStop; - txt = "Stop"; - }, - MENU_ITEM - { - command = EGSTPlayerPause; - txt = "Pause"; - }, - MENU_ITEM - { - command = EGSTRecorderStop; - txt = "Record Stop"; - }, - MENU_ITEM - { - command = EGSTPlayerResume; - txt = "Resume"; - }, - /* MENU_ITEM - { - command = EGSTPlayerVolume; - txt = "Volume"; - cascade=r_volume_cmds; - }, - */ - /* MENU_ITEM - { - command = EGSTPlayerSamplesInfo; - txt = "Sample info"; - cascade=r_sample_info; - }, - */ - /* MENU_ITEM - { - command = EGSTPlayerPadCaps; - txt = "Pad Caps"; - cascade=r_pad_caps; - }, - */ - MENU_ITEM - { - command = EAknSoftkeyExit; - txt = "Exit"; - } - }; - } - -// ----------------------------------------------------------------------------- -// -// Resources for messages. -// -// ----------------------------------------------------------------------------- -// -RESOURCE TBUF32 r_hewb_command1_text { buf="Select mp3/wav/raw file."; } -RESOURCE TBUF32 r_hewb_command2_text { buf="Select mp3/wav/raw New Song!"; } -RESOURCE TBUF32 r_hewb_caption_string { buf="GSTPlayer"; } - - -// ---------------------------------------------------------------------------- -// -// r_helloworldbasic_localisable_app_info -// -// ---------------------------------------------------------------------------- -// -RESOURCE LOCALISABLE_APP_INFO r_gstplayer_localisable_app_info - { - short_caption = "GSTPlayer"; - caption_and_icon = - CAPTION_AND_ICON_INFO - { - caption = "GSTPlayer"; - - number_of_icons = 1; - icon_file = "\\resource\\apps\\gstplayer_aif.mif"; - }; - } - -/* RESOURCE DIALOG r_res_id_for_a_dialog -{ - flags = EAknDialogSelectionList; - buttons = R_AVKON_SOFTKEYS_OK_CANCEL; - items = - { - DLG_LINE - { - type = EAknCtSingleListBox; - id = ESelectionListControl; - control = LISTBOX - { - flags = EAknListBoxSelectionList; - }; - } - }; -} - - - -RESOURCE MENU_BAR r_res_id_for_a_menubar -{ - titles = - { - MENU_TITLE { menu_pane = R_AVKON_MENUPANE_SETTING_LIST ; } - }; -}*/ - -RESOURCE RTXTED r_richtexteditor_rich_text_editor - { - width = KWidth; - height = KHeight; - textlimit = KMaxLength; - flags = EEikEdwinReadOnly | EEikEdwinAvkonDisableCursor; - avkon_flags = EAknEditorFlagEnableScrollBars; - } -// --------------------------------------------------------- -// -// r_musicshop_memory_selection_dialog -// -// --------------------------------------------------------- -// -RESOURCE MEMORYSELECTIONDIALOG r_musicshop_memory_selection_dialog - { - softkey_1 = text_softkey_select; - locations = - { - LOCATION { root_path = text_phone_memory_root_path; }, - LOCATION { root_path = text_memory_card_root_path; } - }; - } - -// End of File - diff -r 5cb7d96a6887 -r 8d4f92b9230e internal/gstplayer/group/gstplayer.mmp --- a/internal/gstplayer/group/gstplayer.mmp Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library 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 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ -/* -* ============================================================================== -* Name : gstplayer.mmp -* Part of : GSTPlayer -* Interface : -* Description : -* Version : -* -* ============================================================================== -*/ - -#include - -TARGET GSTPlayer.exe -TARGETTYPE exe -UID 0x100039CE 0xA000017F -LANG SC -VENDORID VID_DEFAULT -CAPABILITY All -tcb - -SECUREID 0xA000017F -EPOCSTACKSIZE 0x8000 -EPOCHEAPSIZE 0x1000000 0x1000000 - -SOURCEPATH ../src -SOURCE GSTPlayer.cpp -SOURCE GSTPlayerApplication.cpp -SOURCE GSTPlayerAppView.cpp -SOURCE GSTPlayerAppUi.cpp -SOURCE GSTPlayerDocument.cpp -SOURCE RichTextEditor.cpp -SOURCE GlibEventHandler.cpp -SOURCE SymGstreamer.cpp - -SOURCEPATH ../data - -START RESOURCE GSTPlayer.rss -HEADER -TARGETPATH resource/apps -END //RESOURCE - -START RESOURCE GSTPlayer_reg.rss -DEPENDS gstplayer.rsg -#ifdef WINSCW -TARGETPATH /private/10003a3f/apps -#else -TARGETPATH /private/10003a3f/import/apps -#endif -END //RESOURCE - -USERINCLUDE ../inc - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -USERINCLUDE ../../../include/gstreamer -USERINCLUDE ../../../include/gstreamer/gst -USERINCLUDE ../../../include/gstreamer/gst/base -USERINCLUDE ../../../include/gstreamer/gst/controller -USERINCLUDE ../../../include/gstreamer/gst/dataprotocol -USERINCLUDE ../../../include/gstreamer/gst/net - -LIBRARY euser.lib -LIBRARY apparc.lib -LIBRARY cone.lib -LIBRARY eikcore.lib -LIBRARY avkon.lib -LIBRARY commonengine.lib -LIBRARY efsrv.lib -LIBRARY estor.lib -LIBRARY PlatformEnv.lib -LIBRARY CommonDialogs.lib -LIBRARY eikctl.lib -LIBRARY eikcoctl.lib -LIBRARY etext.lib -LIBRARY ws32.lib -LIBRARY libc.lib -LIBRARY libpthread.lib -LIBRARY libdl.lib -LIBRARY libm.lib -LIBRARY libglib.lib -LIBRARY libgmodule.lib -LIBRARY libgobject.lib -LIBRARY libgthread.lib -LIBRARY glibbackend.lib -//LIBRARY libpopt.lib -LIBRARY libz.lib -//LIBRARY pavFeedsLibXml2.lib -LIBRARY libgstreamer.lib -//LIBRARY libgsterrorconcealment.lib -//LIBRARY libgstg711decoderinterface.lib -LIBRARY libgstdevsoundext.lib -LIBRARY MMFDevSound.lib - -// End of File - -SMPSAFE diff -r 5cb7d96a6887 -r 8d4f92b9230e internal/gstplayer/inc/gstplayer.hrh --- a/internal/gstplayer/inc/gstplayer.hrh Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library 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 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ -/* -* ============================================================================== -* Name : helloworldbasic.hrh -* Part of : Helloworldbasic -* Interface : -* Description : -* Version : -* - -* ============================================================================== -*/ - -#ifndef __GSTPLAYER_HRH__ -#define __GSTPLAYER_HRH__ - -// GSTPlayer enumerate command codes -enum TGSTPlayerIds - { - EGSTPlayerNewSong = 0x6001, // start value must not be 0 - EGSTPlayerPlayerTest, - EGSTPlayerRecordTest, - EGSTPlayerPlay, - EGSTPlayerStop, - EGSTRecorderStop, - EGSTPlayerPause, - EGSTPlayerResume, - EGSTPlayerRecordRaw, - EGSTPlayerRecordWav, - EGSTPlayerRecordAmr, - EGSTPlayerRecordG711, - EGSTPlayerRecordG729, - EGSTPlayerRecordIlbc, - EGSTPlayerVolume, - EGSTPlayerCurrentVolume, - EGSTPlayerMaxVolume, - EGSTPlayerVolumeUp, - EGSTPlayerVolumeDown, - EGSTPlayerRightBalance, - EGSTPlayerLeftBalance, - EGSTPlayerGain, - EGSTPlayerCurrentGain, - EGSTPlayerMaxGain, - EGSTPlayerGainUp, - EGSTPlayerGainDown, - EGSTPlayerSamplesPlayed, - EGSTPlayerSamplesRecorded, - EGSTPlayerSamplesInfo, - EGSTPlayerTimePlayed, - - EGSTPlayerSkPadCaps, - EGSTPlayerSourcePadCaps, - - EGSTPlayerSinkPadCaps, - EGSTPlayerSrcPadCaps, - - EGSTPlayerNegotiatedSinkCaps, - EGSTPlayerNegotiatedSrcCaps, - EGSTPlayerRecordAac - - - }; - -#endif // __HELLOWORLDBASIC_HRH__ diff -r 5cb7d96a6887 -r 8d4f92b9230e internal/gstplayer/inc/gstreamer.h --- a/internal/gstplayer/inc/gstreamer.h Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -#include -#include -#include -#include -#include "gstplayerappview.h" - -extern GstElement *pipeline, *source, *wavparse,*sink,*conv,*resample,*decoder; -extern GstBus *bus; - -extern CGSTPlayerAppView *iGstView; - - -int GstreamerNew(TFileName filename); -int GstreamerPlay(TFileName filename); -int gst_play_mp3(); -int gst_play_wave(); -int gst_play_raw(); -int gst_play_amr(); -int gst_play_g711(); -int gst_play_g729(); -int gst_play_ilbc(); - -int gst_record_raw(); -int gst_record_wav(); -int gst_record_amr(); -int gst_record_g711(); -int gst_record_aac(); -int gst_record_g729(); -int gst_record_ilbc(); -int gst_current_volume(); -int gst_max_volume(); -int gst_volume_up(); -int gst_volume_down(); - -void ShownoteL(); - -int gst_current_gain(); -int gst_max_gain(); -int gst_gain_up(); -int gst_gain_down(); - -int gst_balance(); -void samplesplayed(); -void samplesrecorded(); -void samplesrecorded(); -void getsinkpadcaps(); -void negotiatedsinkcaps(); -void getsrcpadcaps(); -void negotiatedsrccaps(); - - diff -r 5cb7d96a6887 -r 8d4f92b9230e internal/gstplayer/src/GSTPlayerappui.cpp --- a/internal/gstplayer/src/GSTPlayerappui.cpp Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,462 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library 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 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ -/* -* ============================================================================== -* Name : gstplayerappui.cpp -* Part of : gstplayer -* Interface : -* Description : -* Version : -* - -* ============================================================================== -*/ - -// INCLUDE FILES -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "GSTPlayer.pan" -#include "GSTPlayerAppUi.h" -#include "GSTPlayerAppView.h" -#include "GSTPlayer.hrh" - -#include "GlibEventHandler.h" -#include "gstreamer.h" - -TFileName fileName; - -_LIT( KHelloFileName, "\\private\\A000017F\\Hello.txt" ); -_LIT( KHelloText, "HELLO WORLD!"); - -// ============================ MEMBER FUNCTIONS =============================== - - -// ----------------------------------------------------------------------------- -// CGSTPlayerAppUi::ConstructL() -// Symbian 2nd phase constructor can leave. -// ----------------------------------------------------------------------------- -// -void CGSTPlayerAppUi::ConstructL() - { - // Initialise app UI with standard value. - BaseConstructL(CAknAppUi::EAknEnableSkin); - // Here the Hello.txt file can be created, if it is not copied automatically. - /* - RFs fsSession; - User::LeaveIfError(fsSession.Connect()); - - RFile file; - - // Create a file to write the text to - if ( file.Replace(fsSession, KHelloFileName, EFileWrite ) != KErrNone ) - { - return; - } - CleanupClosePushL( file ); - - RFileWriteStream outputFileStream( file ); - CleanupClosePushL( outputFileStream ); - outputFileStream << KHelloText; - - CleanupStack::PopAndDestroy(2); // file, outputFileStream - - fsSession.Close(); - */ - - // Create view object - iAppView = CGSTPlayerAppView::NewL(ClientRect() ); - - iGstView = iAppView; - - } -// ----------------------------------------------------------------------------- -// CGSTPlayerAppUi::CGSTPlayerAppUi() -// C++ default constructor can NOT contain any code, that might leave. -// ----------------------------------------------------------------------------- -// -CGSTPlayerAppUi::CGSTPlayerAppUi() - { - // No implementation required - } - -// ----------------------------------------------------------------------------- -// CGSTPlayerAppUi::~CGSTPlayerAppUi() -// Destructor. -// ----------------------------------------------------------------------------- -// -CGSTPlayerAppUi::~CGSTPlayerAppUi() - { - - if (iAppView) - { - delete iAppView; - iAppView = NULL; - } - - } - -// ----------------------------------------------------------------------------- -// CGSTPlayerAppUi::HandleCommandL() -// Takes care of command handling. -// ----------------------------------------------------------------------------- -// -void CGSTPlayerAppUi::HandleCommandL(TInt aCommand) - { - switch (aCommand) - { - case EEikCmdExit: - case EAknSoftkeyExit: - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - gst_object_unref(GST_OBJECT (pipeline)); - - } - Exit(); - break; - - case EGSTPlayerNewSong: - { - /*TDes& aPath; - TBool aMemoryCardStorageAllowed;*/ - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - gst_object_unref(GST_OBJECT (pipeline)); - - } - CAknMemorySelectionDialog* memoryDialog = - CAknMemorySelectionDialog::NewL(ECFDDialogTypeSave, - R_MUSICSHOP_MEMORY_SELECTION_DIALOG, EFalse); - CleanupStack::PushL(memoryDialog); - - CAknMemorySelectionDialog::TMemory - mem(CAknMemorySelectionDialog::EPhoneMemory); - TFileName ignore; - //TFileName path; - if (! (memoryDialog->ExecuteL(mem, &fileName, &ignore) )) - { - // User dnt select the memory location. - // retVal = EFalse; - } - else - { - //aPath.Copy( path ); - } - CleanupStack::PopAndDestroy(); // memoryDialog - - - //if user has pressed cancel button, then just return - if (!ShowDirListL(fileName)) - { - return; - } //end if - if (GstreamerNew(fileName) == -1) - { - // Load a string from the resource file and display it - HBufC* textResource = - StringLoader::LoadLC( R_HEWB_COMMAND1_TEXT); - CAknInformationNote* informationNote; - - informationNote = new ( ELeave ) CAknInformationNote; - - // Show the information Note with - // textResource loaded with StringLoader. - informationNote->ExecuteLD( *textResource); - - // Pop HBuf from CleanUpStack and Destroy it. - CleanupStack::PopAndDestroy(textResource); - - } - - } - break; - case EGSTPlayerPlay: - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - //gst_object_unref (GST_OBJECT (pipeline)); - - } - if (GstreamerNew(fileName) == -1) - { - // Load a string from the resource file and display it - HBufC* textResource = - StringLoader::LoadLC( R_HEWB_COMMAND2_TEXT); - CAknInformationNote* informationNote; - - informationNote = new ( ELeave ) CAknInformationNote; - - // Show the information Note with - // textResource loaded with StringLoader. - informationNote->ExecuteLD( *textResource); - - // Pop HBuf from CleanUpStack and Destroy it. - CleanupStack::PopAndDestroy(textResource); - - } - - break; - case EGSTPlayerStop: - if (pipeline!=NULL) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - gst_object_unref (GST_OBJECT (pipeline)); - pipeline = NULL; - } - break; - case EGSTRecorderStop: - if (pipeline!=NULL) - { - gst_element_send_event (pipeline, gst_event_new_eos ()); - } - break; - - case EGSTPlayerPause: - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_PAUSED); - //gst_object_unref (GST_OBJECT (pipeline)); - - } - break; - - case EGSTPlayerResume: - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PAUSED) - { - - gst_element_set_state(pipeline, GST_STATE_PLAYING); - //gst_object_unref (GST_OBJECT (pipeline)); - - } - break; - - case EGSTPlayerRecordWav: - { - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - //gst_object_unref (GST_OBJECT (pipeline)); - - } - gst_record_wav(); - } - break; - case EGSTPlayerRecordAac: - { - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - //gst_object_unref (GST_OBJECT (pipeline)); - - } - gst_record_aac(); - } - break; - - case EGSTPlayerRecordRaw: - { - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - //gst_object_unref (GST_OBJECT (pipeline)); - - } - gst_record_raw(); - } - break; - - case EGSTPlayerRecordAmr: - { - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - //gst_object_unref (GST_OBJECT (pipeline)); - - } - gst_record_amr(); - } - break; - - case EGSTPlayerRecordG711: - { - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - //gst_object_unref (GST_OBJECT (pipeline)); - - } - gst_record_g711(); - } - break; - case EGSTPlayerRecordG729: - { - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - //gst_object_unref (GST_OBJECT (pipeline)); - - } - gst_record_g729(); - } - break; - case EGSTPlayerRecordIlbc: - { - if (pipeline!=NULL && pipeline ->current_state - == GST_STATE_PLAYING) - { - - gst_element_set_state(pipeline, GST_STATE_NULL); - //gst_object_unref (GST_OBJECT (pipeline)); - - } - gst_record_ilbc(); - } - break; - - case EGSTPlayerCurrentVolume: - gst_current_volume(); - break; - case EGSTPlayerMaxVolume: - gst_max_volume(); - break; - case EGSTPlayerVolumeUp: - gst_volume_up(); - break; - case EGSTPlayerVolumeDown: - gst_volume_down(); - break; - case EGSTPlayerLeftBalance: - case EGSTPlayerRightBalance: - gst_balance(); - break; - case EGSTPlayerCurrentGain: - gst_current_gain(); - break; - case EGSTPlayerMaxGain: - gst_max_gain(); - break; - case EGSTPlayerGainUp: - gst_gain_up(); - break; - case EGSTPlayerGainDown: - gst_gain_down(); - break; - case EGSTPlayerSamplesPlayed: - samplesplayed(); - break; - case EGSTPlayerSamplesRecorded: - samplesrecorded(); - break; - case EGSTPlayerSinkPadCaps: - getsinkpadcaps(); - break; - case EGSTPlayerSrcPadCaps: - getsrcpadcaps(); - break; - case EGSTPlayerNegotiatedSinkCaps: - negotiatedsinkcaps(); - break; - case EGSTPlayerNegotiatedSrcCaps: - negotiatedsrccaps(); - break; - default: - Panic(EGSTPlayerUi); - break; - } - } -// ----------------------------------------------------------------------------- -// Called by the framework when the application status pane -// size is changed. Passes the new client rectangle to the -// AppView -// ----------------------------------------------------------------------------- -// -void CGSTPlayerAppUi::HandleStatusPaneSizeChange() - { - iAppView->SetRect(ClientRect() ); - - } - -TBool CGSTPlayerAppUi::ShowDirListL(TFileName &filePath) - { - - _LIT(KDialogTitle, "Select File"); - - TBool ret = CAknFileSelectionDialog::RunDlgLD(filePath, // on return, contains the selected file's name - PathInfo::PhoneMemoryRootPath(), // default root path for browsing - KDialogTitle, // Dialog's title - 0 // Pointer to class implementing - // MAknFileSelectionObserver. OkToExitL is called - // when user has selected an file. - ); - - return ret; - - } - -void ShowNoteL() - { - // Load a string from the resource file and display it - HBufC* textResource = StringLoader::LoadLC( R_HEWB_COMMAND1_TEXT); - CAknInformationNote* informationNote; - - informationNote = new ( ELeave ) CAknInformationNote; - - // Show the information Note with - // textResource loaded with StringLoader. - informationNote->ExecuteLD( *textResource); - - // Pop HBuf from CleanUpStack and Destroy it. - CleanupStack::PopAndDestroy(textResource); - } -// End of File - diff -r 5cb7d96a6887 -r 8d4f92b9230e internal/gstplayer/src/SymGstreamer.cpp --- a/internal/gstplayer/src/SymGstreamer.cpp Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1268 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library 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 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - -#include "gstreamer.h" -#include "GlibEventHandler.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gstplayerappview.h" - -GstElement *pipeline, *source, *wavparse,*sink,*decoder,*conv,*resample,*record,*fakesink,*filesink,*encoder,*filter,*wavenc, *amrmux, *aacenc, *mp4mux; -GstBus *bus; -GstCaps* caps; -GstState current,pending; -char carray[1024]; - -CGSTPlayerAppView *iGstView; - -GstPad *dssinkpad; -GstCaps *dssinkcap; -GstPad *dssrcpad; -GstCaps *dssrccap; -GstStructure *str; - -gboolean negcaps = FALSE; - -static gboolean print_field (GQuark field, const GValue *value, gpointer pfx); -static void print_caps (const GstCaps *caps, const gchar *pfx); - - - -static void -cb_raw_playback_handoff (GstElement *src, GstBuffer *buffer, GstPad *pad, - gpointer user_data) - { - static gint readbytes = 0; - static gboolean eofReached = FALSE; - - size_t readsize; - gint size; - FILE *f; - GstCaps *bufCaps; - if ( eofReached == TRUE ) - { - //gst_element_set_state (pipeline, GST_STATE_NULL); - // gst_object_unref (GST_OBJECT (pipeline)); - if ( gst_element_send_event (src, gst_event_new_eos ()) == TRUE ) - { - g_print ("posted eos"); - } - - else - { - //g_print ("unable to post eos"); - } - return; - } - - readsize = 0; - f = fopen (carray, "r"); - eofReached = TRUE; - if ( fseek(f, readbytes, 0) == 0 ) - { - readsize = fread (GST_BUFFER_DATA (buffer),1,GST_BUFFER_SIZE (buffer),f); - eofReached = FALSE; - GST_BUFFER_SIZE (buffer) = readsize; - } - fclose(f); - - size = GST_BUFFER_SIZE (buffer); - readbytes += readsize; - if ( (readsize < size) || (readsize == 0) ) - { - eofReached = TRUE; - } - - bufCaps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - gst_buffer_set_caps(buffer,bufCaps); - - } - -static void -cb_play_mp3_handoff (GstElement *fakesrc, - GstBuffer *buffer, - GstPad *pad, - gpointer user_data) -{ -GstCaps *bufCaps; - static gint readbytes = 0; - size_t readsize = 0; - int size = GST_BUFFER_SIZE (buffer); - - FILE *f = fopen (carray, "r"); - fseek(f,readbytes,0); - readsize = fread(GST_BUFFER_DATA (buffer),1,GST_BUFFER_SIZE (buffer),f); - readbytes += readsize; - GST_BUFFER_SIZE (buffer) = readsize; - if(readsize == 0) - { - gst_element_send_event(fakesrc,gst_event_new_eos()); - } - fclose(f); - -} -static void -cb_record_raw_handoff (GstElement *fakesrc, - GstBuffer *buffer, - GstPad *pad, - gpointer user_data) -{ - int size = GST_BUFFER_SIZE (buffer); - //g_print ("[%u]", size); - FILE *f = fopen (carray, "a"); - fwrite(GST_BUFFER_DATA (buffer),1,GST_BUFFER_SIZE (buffer),f); - fclose(f); -} - - -static gboolean -bus_call (GstBus *bus, - GstMessage *msg, - gpointer data) -{ - switch (GST_MESSAGE_TYPE (msg)) { - case GST_MESSAGE_EOS: - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (GST_OBJECT (pipeline)); - break; - case GST_MESSAGE_ERROR: { - gchar *debug; - GError *err; - gst_message_parse_error (msg, &err, &debug); - g_free (debug); - g_print ("Error: %s\n", err->message); - g_error_free (err); - break; - } - default: - break; - } - - return TRUE; -} - - -static void -new_pad_cb (GstElement *wavparse, GstPad *new_pad, gpointer pipeline) - { - //GstElement *sink,*conv,*resample; - gst_element_set_state ((_GstElement *)pipeline, GST_STATE_PAUSED); - sink = gst_element_factory_make ("devsoundsink", "sink"); - conv = gst_element_factory_make ("audioconvert", "audioconvert"); - if (!conv) { - g_print ("could not create \"audioconvert\" element!"); - return; - } - resample = gst_element_factory_make ("audioresample", "audioresample"); - if (!resample) { - g_print ("could not create \"audioresample\" element!"); - return ; - } - gst_bin_add_many(GST_BIN (pipeline), conv, resample, sink, NULL); - - // if (!gst_element_link (wavparse, sink)) - // g_error ("link(wavparse, sink) failed!\n"); - - if(! gst_element_link_many (wavparse,conv, resample, sink, NULL)) - g_print ("link(wavparse,conv,remaple sink) failed!\n"); - - gst_element_set_state ((_GstElement *)pipeline, GST_STATE_PLAYING); - } - - #define FILENAME 1024 - int GstreamerNew(TFileName filename) - { - size_t ret; - - ret = wcstombs(carray, (const wchar_t *)filename.PtrZ(), FILENAME); - int file_type=0; - - - - char *p; - p = strrchr(carray, '.'); - - if ((p != NULL) && (strcmp(p, ".mp3") == 0)) - { - file_type=2; - } - else if ((p != NULL) && (strcmp(p, ".wav") == 0)) - { - file_type=1; - } - else if ((p != NULL) && (strcmp(p, ".raw") == 0)) - { - file_type=3; - } - else if ((p != NULL) && (strcmp(p, ".amr") == 0)) - { - file_type=4; - } - else if ((p != NULL) && (strcmp(p, ".g711") == 0)) - { - file_type=5; - } - else if ((p != NULL) && (strcmp(p, ".g729") == 0)) - { - file_type=6; - } - else if ((p != NULL) && (strcmp(p, ".lbc") == 0)) - { - file_type=7; - } - else - return -1; - - if(file_type==1) - { - gst_play_wave(); - } - else if(file_type==2) - { - gst_play_mp3(); - } - else if(file_type==3) - { - gst_play_raw(); - } - else if(file_type==4) - { - gst_play_amr(); - } - else if(file_type==5) - { - gst_play_g711(); - } - else if(file_type==6) - { - gst_play_g729(); - } - else if(file_type==7) - { - gst_play_ilbc(); - } - - else - { - return 0; - } - } - - -int gst_play_mp3() -{ - /* create elements */ - gboolean link_ok; - - pipeline = gst_pipeline_new ("pipeline"); - source = gst_element_factory_make ("filesrc", "filesrc"); - //sink = gst_element_factory_make ("fakesink", "sink"); - sink = gst_element_factory_make ("devsoundsink", "sink"); - - caps = gst_caps_new_simple ("audio/mp3", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 16000, - "channels", G_TYPE_INT, 2, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch( bus, bus_call, NULL); - gst_object_unref (bus); - - g_object_set (G_OBJECT (source), "location", carray, NULL); - - gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL); - - //gst_element_link (source, sink); - link_ok = gst_element_link_filtered (source, sink, caps); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - return 0; -} - - int gst_play_wave() - { - /* create elements */ - pipeline = gst_pipeline_new ("pipeline"); - source = gst_element_factory_make ("filesrc", "pavsrc"); - wavparse = gst_element_factory_make ("wavparse", "parse"); - - /* set filename property on the file source */ - g_object_set (G_OBJECT (source), "location", carray, NULL); - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch (bus, bus_call, NULL); - gst_object_unref (bus); - gst_bin_add_many (GST_BIN (pipeline), source, wavparse, NULL); - if (!gst_element_link (source, wavparse)) - g_error ("link(src, wavparse) failed!\n"); - - - g_signal_connect (wavparse, "pad-added", G_CALLBACK (new_pad_cb),pipeline); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - return 0; - } - - int gst_record_wav() - { - - iGstView->DrawText(_L("Recording Wave"),KRgbBlack); - - /* create a new bin to hold the elements */ - pipeline = gst_pipeline_new("pipeline"); - - record = gst_element_factory_make("devsoundsrc", "record_audio"); - if (!record) - { - g_print("could not create \"record\" element!"); - return -1; - } - //g_object_set (G_OBJECT (record), "num-buffers", 5000 , NULL); - filesink = gst_element_factory_make("filesink", "filesink"); - if (!filesink) - { - g_print("could not create \"filesink\" element!"); - return -1; - } - - wavenc = gst_element_factory_make("wavenc", "wavencoder"); - if (!wavenc) - { - g_print("could not create \"wavenc\" element!"); - return -1; - } - - _LIT(KFILENAME,"c:\\data\\test.wav"); - TFileName fn; - fn.Append(KFILENAME); - TInt ret; - // char carray[FILENAME]; - ret = wcstombs(carray, (const wchar_t *)fn.PtrZ(), FILENAME); - - g_object_set(G_OBJECT (filesink), "location", carray, NULL); - bus = gst_pipeline_get_bus(GST_PIPELINE (pipeline)); - gst_bus_add_watch(bus, bus_call, NULL); - gst_object_unref(bus); - - /* add objects to the main pipeline */ - gst_bin_add_many(GST_BIN (pipeline),record,wavenc,filesink, NULL); - - /* link the elements */ - //gst_element_link_many(record, wavenc,filesink, NULL); - caps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 16000, - "channels", G_TYPE_INT, 1, NULL); - - gst_element_link_filtered (record, wavenc, caps); - gst_element_link (wavenc, filesink); - gst_caps_unref (caps); - iGstView->DrawText(_L("pipeline created\n"),KRgbBlack); - /* start recording */ - gst_element_set_state(pipeline, GST_STATE_PLAYING); - iGstView->DrawText(_L("set to play wave file\n"),KRgbBlack); - return 0; - } - - - int gst_record_aac() - { - GstPad *qtsinkpad,*aacencsrcpad; - iGstView->DrawText(_L("Recording aac"),KRgbBlack); - - /* create a new bin to hold the elements */ - pipeline = gst_pipeline_new("pipeline"); - - record = gst_element_factory_make("devsoundsrc", "record_audio"); - if (!record) - { - g_print("could not create \"record\" element!"); - return -1; - } - //g_object_set (G_OBJECT (record), "num-buffers", 5000 , NULL); - filesink = gst_element_factory_make("filesink", "filesink"); - if (!filesink) - { - g_print("could not create \"filesink\" element!"); - return -1; - } - - aacenc = gst_element_factory_make("nokiaaacenc", "nokiaaacenc"); - if (!aacenc) - { - g_print("could not create \"aacenc\" element!"); - return -1; - } - - mp4mux = gst_element_factory_make("mp4mux", "mp4mux"); - if (!mp4mux) - { - g_print("could not create \"mp4mux\" element!"); - return -1; - } - //name = gst_pad_get_name( sinkpad ); - - _LIT(KFILENAME,"c:\\data\\test.mp4"); - TFileName fn; - fn.Append(KFILENAME); - TInt ret; - // char carray[FILENAME]; - ret = wcstombs(carray, (const wchar_t *)fn.PtrZ(), FILENAME); - - g_object_set(G_OBJECT (filesink), "location", carray, NULL); - bus = gst_pipeline_get_bus(GST_PIPELINE (pipeline)); - gst_bus_add_watch(bus, bus_call, NULL); - gst_object_unref(bus); - - /* add objects to the main pipeline */ - gst_bin_add_many(GST_BIN (pipeline),record,aacenc,mp4mux,filesink, NULL); - - /* link the elements */ - //gst_element_link_many(record, aacenc,filesink, NULL); - caps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 16000, - "channels", G_TYPE_INT, 1, NULL); - - gst_element_link_filtered (record, aacenc, caps); - qtsinkpad = gst_element_get_request_pad( mp4mux, "audio_%d"); - aacencsrcpad = gst_element_get_pad( aacenc, "src"); - if (gst_pad_link (aacencsrcpad,qtsinkpad) != GST_PAD_LINK_OK) { - - g_print("gst_pad_link (aacencsrcpad,qtsinkpad) failed"); - return -1; - } - //gst_element_link (aacenc, filesink); - gst_element_link (mp4mux, filesink); - gst_caps_unref (caps); - iGstView->DrawText(_L("pipeline created\n"),KRgbBlack); - /* start recording */ - gst_element_set_state(pipeline, GST_STATE_PLAYING); - iGstView->DrawText(_L("set to play aac file\n"),KRgbBlack); - return 0; - } - - int gst_record_amr() - { - iGstView->DrawText(_L("Recording AMR-NB"),KRgbRed); - - /* create a new bin to hold the elements */ - pipeline = gst_pipeline_new ("pipeline"); - - //g_print ("pipeline created"); - record = gst_element_factory_make ("devsoundsrc", "record_audio"); - // encoder = gst_element_factory_make ("wavenc", NULL); - if (!record) { - g_print ("could not create \"record\" element!"); - iGstView->DrawText(_L("Devsound src not available"),KRgbRed); - return -1; - } - - - amrmux = gst_element_factory_make ("amrmux", "muxer"); - // encoder = gst_element_factory_make ("wavenc", NULL); - if (!amrmux) { - g_print ("could not create \"amrmuxer\" element!"); - iGstView->DrawText(_L("amrmuxer not available"),KRgbRed); - return -1; - } - - filesink = gst_element_factory_make("filesink", "filesink"); - if (!filesink) - { - g_print("could not create \"filesink\" element!"); - return -1; - } - - caps = gst_caps_new_simple ("audio/amr", - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - - g_object_set (G_OBJECT (record), - "blocksize", 1280, - NULL); - - _LIT(KFILENAME,"c:\\data\\recordtest.amr"); - TFileName fn; - fn.Append(KFILENAME); - TInt ret; - ret = wcstombs(carray, (const wchar_t *)fn.PtrZ(), FILENAME); - g_object_set(G_OBJECT (filesink), "location", carray, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch (bus, bus_call, NULL); - gst_object_unref (bus); - - - /* add objects to the main pipeline */ - gst_bin_add_many(GST_BIN (pipeline),record,amrmux,filesink , NULL); - /* link the elements */ - gst_element_link_filtered (record, amrmux, caps); - - gst_element_link( amrmux, filesink ); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - return 0; - } - - int gst_record_g711() - { - /* create a new bin to hold the elements */ - pipeline = gst_pipeline_new ("pipeline"); - - //g_print ("pipeline created"); - record = gst_element_factory_make ("devsoundsrc", "record_audio"); - // encoder = gst_element_factory_make ("wavenc", NULL); - if (!record) { - g_print ("could not create \"record\" element!"); - return -1; - } - - filesink = gst_element_factory_make("filesink", "filesink"); - if (!filesink) - { - g_print("could not create \"filesink\" element!"); - return -1; - } - - caps = gst_caps_new_simple ("audio/x-alaw", - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - g_object_set (G_OBJECT (record), - "blocksize", 1280, - NULL); - - _LIT(KFILENAME,"c:\\data\\recordtest.g711"); - TFileName fn; - fn.Append(KFILENAME); - TInt ret; - ret = wcstombs(carray, (const wchar_t *)fn.PtrZ(), FILENAME); - g_object_set(G_OBJECT (filesink), "location", carray, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch (bus, bus_call, NULL); - gst_object_unref (bus); - - - /* add objects to the main pipeline */ - gst_bin_add_many(GST_BIN (pipeline),record,filesink , NULL); - /* link the elements */ - gst_element_link_filtered (record, filesink, caps); - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - return 0; - } - - int gst_record_g729() - { - /* create a new bin to hold the elements */ - pipeline = gst_pipeline_new ("pipeline"); - - record = gst_element_factory_make ("devsoundsrc", "record_audio"); - if (!record) { - g_print ("could not create \"record\" element!"); - return -1; - } - - filesink = gst_element_factory_make("filesink", "filesink"); - if (!filesink) - { - g_print("could not create \"filesink\" element!"); - return -1; - } - - caps = gst_caps_new_simple ("audio/g729", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - g_object_set (G_OBJECT (record), - "blocksize", 1280, - NULL); - - _LIT(KFILENAME,"c:\\data\\recordtest.g729"); - TFileName fn; - fn.Append(KFILENAME); - TInt ret; - ret = wcstombs(carray, (const wchar_t *)fn.PtrZ(), FILENAME); - g_object_set(G_OBJECT (filesink), "location", carray, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch (bus, bus_call, NULL); - gst_object_unref (bus); - - - /* add objects to the main pipeline */ - gst_bin_add_many(GST_BIN (pipeline),record,filesink , NULL); - /* link the elements */ - gst_element_link_filtered (record, filesink, caps); - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - return 0; - } - - int gst_record_ilbc() - { - /* create a new bin to hold the elements */ - pipeline = gst_pipeline_new ("pipeline"); - - record = gst_element_factory_make ("devsoundsrc", "record_audio"); - if (!record) { - g_print ("could not create \"record\" element!"); - return -1; - } - - filesink = gst_element_factory_make("filesink", "filesink"); - if (!filesink) - { - g_print("could not create \"filesink\" element!"); - return -1; - } - - caps = gst_caps_new_simple ("audio/ilbc", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - g_object_set (G_OBJECT (record), - "blocksize", 1280, - NULL); - - _LIT(KFILENAME,"c:\\data\\recordtest.lbc"); - TFileName fn; - fn.Append(KFILENAME); - TInt ret; - ret = wcstombs(carray, (const wchar_t *)fn.PtrZ(), FILENAME); - g_object_set(G_OBJECT (filesink), "location", carray, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch (bus, bus_call, NULL); - gst_object_unref (bus); - - - /* add objects to the main pipeline */ - gst_bin_add_many(GST_BIN (pipeline),record,filesink , NULL); - /* link the elements */ - gst_element_link_filtered (record, filesink, caps); - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - return 0; - } - - int gst_record_raw() - { - - /* create a new bin to hold the elements */ - pipeline = gst_pipeline_new ("pipeline"); - - //g_print ("pipeline created"); - record = gst_element_factory_make ("devsoundsrc", "record_audio"); - // encoder = gst_element_factory_make ("wavenc", NULL); - if (!record) { - g_print ("could not create \"record\" element!"); - return -1; - } - //g_print ("record created"); - filesink = gst_element_factory_make("filesink", "filesink"); - if (!filesink) - { - g_print("could not create \"filesink\" element!"); - return -1; - } - //GstRingBufferSpec - //g_print ("sink created"); - caps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - //g_print ("caps created"); - g_object_set (G_OBJECT (record), - //"signal-handoffs", TRUE, - "blocksize", 1280, - // "gain",10000, - NULL); - - /*g_object_set (G_OBJECT (fakesink), - "signal-handoffs", TRUE, - "sizemax", 4096, - "sizetype", 2, NULL);*/ - - _LIT(KFILENAME,"c:\\data\\test.raw"); - TFileName fn; - fn.Append(KFILENAME); - TInt ret; - //char carray[FILENAME]; - carray[0]='\0'; - ret = wcstombs(carray, (const wchar_t *)fn.PtrZ(), FILENAME); - - - g_object_set (G_OBJECT (filesink), "location", carray,"buffer-size",1280, NULL); - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch (bus, bus_call, NULL); - gst_object_unref (bus); - - - /* add objects to the main pipeline */ - gst_bin_add_many(GST_BIN (pipeline),record,filesink , NULL); - //g_print ("added to pipe"); - /* link the elements */ - //gst_element_link(record,/*encoder,*/ fakesink/*audiosink*/); - gst_element_link_filtered (record, filesink, caps); - //g_signal_connect (fakesink, "handoff", G_CALLBACK (cb_record_raw_handoff), NULL); - /* start recording */ - // g_print ("start pipe"); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - return 0; - } - - - int gst_play_raw() - { - /* create elements */ - gboolean link_ok; - - pipeline = gst_pipeline_new ("pipeline"); - source = gst_element_factory_make ("filesrc", "filesrc"); - //sink = gst_element_factory_make ("fakesink", "sink"); - sink = gst_element_factory_make ("devsoundsink", "sink"); - -caps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch( bus, bus_call, NULL); - gst_object_unref (bus); - - /*g_object_set (G_OBJECT(source), - "signal-handoffs", TRUE, - //"num-buffers", 4, - "sizemax", 4096, - "sizetype", 2, - NULL);*/ - - g_object_set (G_OBJECT (source), "location", carray, NULL); -// g_signal_connect (source, "handoff", G_CALLBACK (cb_raw_playback_handoff), NULL); - - gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL); - - //gst_element_link (source, sink); - link_ok = gst_element_link_filtered (source, sink, caps); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - -while (caps->refcount > 1) - { - gst_caps_unref (caps); - } - gst_caps_unref (caps); - - - return 0; - } - - int gst_play_amr() - { - /* create elements */ - gboolean link_ok; - - pipeline = gst_pipeline_new ("pipeline"); - source = gst_element_factory_make ("filesrc", "filesrc"); - //sink = gst_element_factory_make ("fakesink", "sink"); - sink = gst_element_factory_make ("devsoundsink", "sink"); - - caps = gst_caps_new_simple ("audio/amr", - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch( bus, bus_call, NULL); - gst_object_unref (bus); - - g_object_set (G_OBJECT (source), "location", carray, NULL); - - gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL); - - link_ok = gst_element_link_filtered (source, sink, caps); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - return 0; - } - - int gst_play_g711() - { - /* create elements */ - gboolean link_ok; - - pipeline = gst_pipeline_new ("pipeline"); - source = gst_element_factory_make ("filesrc", "filesrc"); - sink = gst_element_factory_make ("devsoundsink", "sink"); - - caps = gst_caps_new_simple ("audio/x-alaw", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch( bus, bus_call, NULL); - gst_object_unref (bus); - - g_object_set (G_OBJECT (source), "location", carray, NULL); - gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL); - - link_ok = gst_element_link_filtered (source, sink, caps); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - return 0; - } - int gst_play_g729() - { - /* create elements */ - gboolean link_ok; - - pipeline = gst_pipeline_new ("pipeline"); - source = gst_element_factory_make ("filesrc", "filesrc"); - sink = gst_element_factory_make ("devsoundsink", "sink"); - - caps = gst_caps_new_simple ("audio/g729", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch( bus, bus_call, NULL); - gst_object_unref (bus); - - g_object_set (G_OBJECT (source), "location", carray, NULL); - - gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL); - - link_ok = gst_element_link_filtered (source, sink, caps); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - return 0; - } - int gst_play_ilbc() - { - /* create elements */ - gboolean link_ok; - - pipeline = gst_pipeline_new ("pipeline"); - source = gst_element_factory_make ("filesrc", "filesrc"); - sink = gst_element_factory_make ("devsoundsink", "sink"); - - caps = gst_caps_new_simple ("audio/ilbc", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed",G_TYPE_BOOLEAN, TRUE, - "endianness",G_TYPE_INT, G_BYTE_ORDER, - "rate", G_TYPE_INT, 8000, - "channels", G_TYPE_INT, 1, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch( bus, bus_call, NULL); - gst_object_unref (bus); - - g_object_set (G_OBJECT (source), "location", carray, NULL); - - gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL); - - link_ok = gst_element_link_filtered (source, sink, caps); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - return 0; - } - - - //****** - int gst_current_volume() - { - if(!sink) - { - iGstView->DrawText(_L("Devsound sink not available"),KRgbRed); - return -1; - } - int vol; - TBuf<25> currentvolume(_L("current volume ")); - g_object_get(G_OBJECT(sink), - "volume",&vol,NULL); - - currentvolume.AppendNum(vol); - - iGstView->DrawText(currentvolume,KRgbBlack); - return 0; - } - - int gst_max_volume() - { - if(!sink) - { - iGstView->DrawText(_L("Devsound sink not available"),KRgbRed); - return -1; - } - - int maxvol; - TBuf<25> maxvolume(_L("max volume ")); - - g_object_get(G_OBJECT(sink), - "maxvolume",&maxvol,NULL); - - maxvolume.AppendNum(maxvol); - - iGstView->DrawText(maxvolume,KRgbBlack); - return 0; - - } - int gst_volume_up() - { - - if(!sink) - { - iGstView->DrawText(_L("Devsound sink not available"),KRgbRed); - return -1; - } - iGstView->DrawText(_L("volume up"),KRgbBlack); - int maxvol; - g_object_get(G_OBJECT(sink), - "maxvolume",&maxvol,NULL); - g_object_set (G_OBJECT (sink), - "volume", maxvol, NULL); - return 0; - } - - int gst_volume_down() - { - if(!sink) - { - iGstView->DrawText(_L("Devsound sink not available"),KRgbRed); - return -1; - } - - iGstView->DrawText(_L("volume down"),KRgbBlack); - int maxvol; - g_object_get(G_OBJECT(sink), - "maxvolume",&maxvol,NULL); - g_object_set (G_OBJECT (sink), - "volume", maxvol/2, NULL); - return 0; - } - - int gst_current_gain() - { - if(!record) - { - iGstView->DrawText(_L("Devsound source not available"),KRgbRed); - return -1; - } - int gain; - TBuf<25> currentgain(_L("current gain ")); - g_object_get(G_OBJECT(record), - "gain",&gain,NULL); - - currentgain.AppendNum(gain); - - iGstView->DrawText(currentgain,KRgbBlack); - return 0; - } - - int gst_max_gain() - { - if(!record) - { - iGstView->DrawText(_L("Devsound source not available"),KRgbRed); - return -1; - } - - int max; - TBuf<25> maxgain(_L("max gain ")); - - g_object_get(G_OBJECT(record), - "maxgain",&max,NULL); - - maxgain.AppendNum(max); - - iGstView->DrawText(maxgain,KRgbBlack); - return 0; - - } - int gst_gain_up() - { - - if(!record) - { - iGstView->DrawText(_L("Devsound source not available"),KRgbRed); - return -1; - } - int max; - g_object_get(G_OBJECT(record), - "maxgain",&max,NULL); - - iGstView->DrawText(_L("gain up"),KRgbBlack); - g_object_set (G_OBJECT (record), - "gain", max, NULL); - return 0; - } - - int gst_gain_down() - { - if(!record) - { - iGstView->DrawText(_L("Devsound source not available"),KRgbRed); - return -1; - } - int max; - g_object_get(G_OBJECT(record), - "maxgain",&max,NULL); - iGstView->DrawText(_L("gain down"),KRgbBlack); - g_object_set (G_OBJECT (sink), - "gain", max/2, NULL); - return 0; - } - - - - int gst_balance() - { - if(!sink) - { - iGstView->DrawText(_L("Devsound sink not available"),KRgbRed); - return -1; - } - - iGstView->DrawText(_L("balance"),KRgbBlack); - /* g_object_set (G_OBJECT (sink), - "left balance", 5000, - "right balance",5000,NULL); - */ - return 0; - } - - void samplesplayed() - { - if(!sink) - { - iGstView->DrawText(_L("Devsound sink not available"),KRgbRed); - } - int samples; - TBuf<25> samplesplayed(_L("samples played ")); - g_object_get (G_OBJECT (sink), - "samples played", &samples, NULL); - - samplesplayed.AppendNum(samples); - iGstView->DrawText(samplesplayed,KRgbBlack); - } - - void samplesrecorded() - { - if(!record) - { - iGstView->DrawText(_L("Devsound src not available"),KRgbRed); - } - int samples; - TBuf<25> samplesrecorded(_L("samples recorded ")); - g_object_get (G_OBJECT (record), - "samples recorded", &samples, NULL); - - samplesrecorded.AppendNum(samples); - iGstView->DrawText(samplesrecorded,KRgbBlack); - } - - static gboolean print_field (GQuark field, const GValue *value, gpointer pfx) - { - gchar *str = gst_value_serialize (value); - - const gchar* c; - - RDebug::Printf("%s %15s: %s\n", (gchar *) pfx, c = g_quark_to_string (field), str); - - if(negcaps) - { - TPtrC8 property((const TText8*)c); - TPtrC8 val((const TText8*)str); - TBuf<10> appdval; - appdval.Copy(val); - - TBuf<25> name; - name.Copy(property); - name.Append(':'); - name.Append(appdval); - - iGstView->DrawText(name,KRgbBlack); - } - g_free (str); - return TRUE; - } - - static void print_caps (const GstCaps *caps, const gchar *pfx) - { - guint i; - - g_return_if_fail (caps != NULL); - - if (gst_caps_is_any (caps)) { - RDebug::Printf("%sANY\n", pfx); - return; - } - if (gst_caps_is_empty (caps)) { - RDebug::Printf("%sEMPTY\n", pfx); - return; - } - const gchar *c; - for (i = 0; i < gst_caps_get_size (caps); i++) { - GstStructure *structure = gst_caps_get_structure (caps, i); - - RDebug::Printf("%s%s\n", pfx,c = gst_structure_get_name (structure)); - - TPtrC8 fmt((const TText8*)c); - - TBuf<25> name; - name.Copy(fmt); - - iGstView->DrawText(name,KRgbBlack); - - gst_structure_foreach (structure, print_field, (gpointer) pfx); - } - } - - void getsinkpadcaps() - { - RDebug::Print(_L("Devsound Pad Caps")); - if(!sink) - { - iGstView->DrawText(_L("Devsound sink not available"),KRgbRed); - return; - } - negcaps = FALSE; - dssinkpad = gst_element_get_pad (sink, "sink"); - dssinkcap = gst_pad_get_caps (dssinkpad); - - print_caps (dssinkcap, " "); - } - - void negotiatedsinkcaps() - { - RDebug::Print(_L("Negotiated caps")); - if(!sink) - { - iGstView->DrawText(_L("Devsound sink not available"),KRgbRed); - return; - } - negcaps = TRUE; - dssinkpad = gst_element_get_pad (sink, "sink"); - dssinkcap = gst_pad_get_negotiated_caps (dssinkpad); - - print_caps (dssinkcap, " "); - } - - void getsrcpadcaps() - { - RDebug::Print(_L("Devsound Source Pad Caps")); - if(!record) - { - iGstView->DrawText(_L("Devsound src not available"),KRgbRed); - return; - } - negcaps = FALSE; - dssrcpad = gst_element_get_pad (record, "src"); - dssrccap = gst_pad_get_caps (dssrcpad); - - print_caps (dssrccap, " "); - } - - void negotiatedsrccaps() - { - RDebug::Print(_L("Negotiated src caps")); - if(!record) - { - iGstView->DrawText(_L("Devsound src not available"),KRgbRed); - return; - } - negcaps = TRUE; - dssrcpad = gst_element_get_pad (record, "src"); - dssrccap = gst_pad_get_negotiated_caps (dssrcpad); - - print_caps (dssrccap, " "); - - } diff -r 5cb7d96a6887 -r 8d4f92b9230e internal/miscfiles/copyplugins.bat --- a/internal/miscfiles/copyplugins.bat Fri May 28 18:11:17 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -md \epoc32\release\winscw\udeb\z\sys\bin\plugins - -COPY \epoc32\release\winscw\udeb\libgstcoreelements.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstcoreelements.dll -COPY \epoc32\release\winscw\udeb\libgstcoreindexers.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstcoreindexers.dll -COPY \epoc32\release\winscw\udeb\libgstwavparse.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstwavparse.dll -COPY \epoc32\release\winscw\udeb\libgstwavenc.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstwavenc.dll -COPY \epoc32\release\winscw\udeb\libgstdevsoundsink.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstdevsoundsink.dll -COPY \epoc32\release\winscw\udeb\libgstdevsoundsrc.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstdevsoundsrc.dll -COPY \epoc32\release\winscw\udeb\libgstaudioconvert.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstaudioconvert.dll -COPY \epoc32\release\winscw\udeb\libgstaudioresample.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstaudioresample.dll -COPY \epoc32\release\winscw\udeb\libgstaudiotestsrc.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstaudiotestsrc.dll -COPY \epoc32\release\winscw\udeb\libgstdecodebin.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstdecodebin.dll -COPY \epoc32\release\winscw\udeb\libgstdecodebin2.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstdecodebin2.dll -COPY \epoc32\release\winscw\udeb\libgstplaybin.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstplaybin.dll -COPY \epoc32\release\winscw\udeb\libgsttypefindfunctions.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgsttypefindfunctions.dll -COPY \epoc32\release\winscw\udeb\libgstqueue2.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstqueue2.dll -COPY \epoc32\release\winscw\udeb\libgstaudiorate.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstaudiorate.dll -COPY \epoc32\release\winscw\udeb\libgstautodetect.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstautodetect.dll -COPY \epoc32\release\winscw\udeb\libgstapp.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstapp.dll -COPY \epoc32\release\winscw\udeb\libgstsubparse.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstsubparse.dll -COPY \epoc32\release\winscw\udeb\libgstgdp.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstgdp.dll -COPY \epoc32\release\winscw\udeb\libgstadder.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstadder.dll -COPY \epoc32\release\winscw\udeb\libgstvolume.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstvolume.dll -COPY \epoc32\release\winscw\udeb\libgsttcp.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgsttcp.dll -COPY \epoc32\release\winscw\udeb\gstqtmux.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\gstqtmux.dll -COPY \epoc32\release\winscw\udeb\libgstnokiaaacenc.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstnokiaaacenc.dll -COPY \epoc32\release\winscw\udeb\libgstamrmux.dll \epoc32\release\winscw\udeb\z\sys\bin\plugins\libgstamrmux.dll \ No newline at end of file diff -r 5cb7d96a6887 -r 8d4f92b9230e rom/gstreamer.iby --- a/rom/gstreamer.iby Fri May 28 18:11:17 2010 -0500 +++ b/rom/gstreamer.iby Fri Jun 25 17:18:46 2010 -0500 @@ -48,7 +48,6 @@ file=ABI_DIR\BUILD_DIR\libgstriff.dll SHARED_LIB_DIR\libgstriff.dll file=ABI_DIR\BUILD_DIR\libgsttag.dll SHARED_LIB_DIR\libgsttag.dll file=ABI_DIR\BUILD_DIR\libgstvideo.dll SHARED_LIB_DIR\libgstvideo.dll -file=ABI_DIR\BUILD_DIR\libgstphotography.dll SHARED_LIB_DIR\libgstphotography.dll //file=ABI_DIR\BUILD_DIR\libgstvideorate.dll SHARED_LIB_DIR\libgstvideorate.dll //file=ABI_DIR\BUILD_DIR\libgstvideoscale.dll SHARED_LIB_DIR\libgstvideoscale.dll //file=ABI_DIR\BUILD_DIR\libgstvideotestsrc.dll SHARED_LIB_DIR\libgstvideotestsrc.dll diff -r 5cb7d96a6887 -r 8d4f92b9230e sis/gstreamer_framework.pkg Binary file sis/gstreamer_framework.pkg has changed