Audacity  3.0.3
Public Member Functions | Private Attributes | List of all members
GStreamerImportFileHandle Class Referencefinal

! Does actual import, returned by GStreamerImportPlugin::Open More...

Inheritance diagram for GStreamerImportFileHandle:
[legend]
Collaboration diagram for GStreamerImportFileHandle:
[legend]

Public Member Functions

 GStreamerImportFileHandle (const wxString &name)
 
virtual ~GStreamerImportFileHandle ()
 
bool Init ()
 
TranslatableString GetFileDescription () override
 
ByteCount GetFileUncompressedBytes () override
 
wxInt32 GetStreamCount () override
 
const TranslatableStringsGetStreamInfo () override
 
void SetStreamUsage (wxInt32 index, bool use) override
 
int Import (TrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) override
 
void OnPadAdded (GstPad *pad)
 
void OnPadRemoved (GstPad *pad)
 
bool ProcessBusMessage (bool &success)
 
void OnTag (GstAppSink *appsink, GstTagList *tags)
 
void OnNewSample (GStreamContext *c, GstSample *sample)
 
- Public Member Functions inherited from ImportFileHandle
 ImportFileHandle (const FilePath &filename)
 
virtual ~ImportFileHandle ()
 
void CreateProgress ()
 
virtual ProgressResult Import (WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags)=0
 

Private Attributes

TranslatableStrings mStreamInfo
 Array of stream descriptions. Length is the same as mStreams. More...
 
Tags mTags
 Tags to be passed back to Audacity. More...
 
TrackFactory * mTrackFactory
 Factory to create tracks when samples arrive. More...
 
GstString mUri
 URI of file. More...
 
GstObjHandle< GstElement > mPipeline
 GStreamer pipeline. More...
 
GstObjHandle< GstBus > mBus
 Message bus. More...
 
GstElement * mDec
 uridecodebin element More...
 
bool mAsyncDone
 true = 1st async-done message received More...
 
GMutex mStreamsLock
 Mutex protecting the mStreams array. More...
 
std::vector< std::unique_ptr< GStreamContext > > mStreams
 Array of pointers to stream contexts. More...
 

Additional Inherited Members

- Public Types inherited from ImportFileHandle
using ProgressResult = BasicUI::ProgressResult
 
using ByteCount = unsigned long long
 
- Static Public Member Functions inherited from ImportFileHandle
static sampleFormat ChooseFormat (sampleFormat effectiveFormat)
 Choose appropriate format, which will not be narrower than the specified one. More...
 
- Protected Member Functions inherited from ImportFileHandle
std::shared_ptr< WaveTrackNewWaveTrack (WaveTrackFactory &trackFactory, sampleFormat effectiveFormat, double rate)
 Build a wave track with appropriate format, which will not be narrower than the specified one. More...
 
- Protected Attributes inherited from ImportFileHandle
FilePath mFilename
 
std::unique_ptr< ProgressDialogmProgress
 

Detailed Description

! Does actual import, returned by GStreamerImportPlugin::Open

An ImportFileHandle for GStreamer data.

Definition at line 158 of file ImportGStreamer.cpp.

Constructor & Destructor Documentation

◆ GStreamerImportFileHandle()

GStreamerImportFileHandle::GStreamerImportFileHandle ( const wxString &  name)

Definition at line 839 of file ImportGStreamer.cpp.

841 {
842  mDec = NULL;
843  mTrackFactory = NULL;
844  mAsyncDone = false;
845 
846  g_mutex_init(&mStreamsLock);
847 }

References mAsyncDone, mDec, mStreamsLock, and mTrackFactory.

◆ ~GStreamerImportFileHandle()

GStreamerImportFileHandle::~GStreamerImportFileHandle ( )
virtual

Definition at line 851 of file ImportGStreamer.cpp.

852 {
853  // Make sure the pipeline isn't running
854  if (mPipeline)
855  {
856  gst_element_set_state(mPipeline.get(), GST_STATE_NULL);
857  }
858 
859  // Delete all of the contexts
860  if (mStreams.size())
861  {
862  // PRL: is the FIFO destruction order important?
863  // If not, then you could simply clear mStreams.
864 
865  {
866  g_mutex_locker locker{ mStreamsLock };
867  while (mStreams.size() > 0)
868  {
869  // remove context from the array
870  mStreams.erase(mStreams.begin());
871  }
872  }
873 
874  // Done with the context array
875  }
876 
877  // Release the decoder
878  if (mDec != NULL)
879  {
880  gst_bin_remove(GST_BIN(mPipeline.get()), mDec);
881  }
882 
883  g_mutex_clear(&mStreamsLock);
884 }

References mDec, mPipeline, mStreams, and mStreamsLock.

Member Function Documentation

◆ GetFileDescription()

TranslatableString GStreamerImportFileHandle::GetFileDescription ( )
overridevirtual

Implements ImportFileHandle.

Definition at line 1001 of file ImportGStreamer.cpp.

1002 {
1003  return DESC;
1004 }

References DESC.

◆ GetFileUncompressedBytes()

auto GStreamerImportFileHandle::GetFileUncompressedBytes ( )
overridevirtual

Implements ImportFileHandle.

Definition at line 1009 of file ImportGStreamer.cpp.

1010 {
1011  return 0;
1012 }

◆ GetStreamCount()

wxInt32 GStreamerImportFileHandle::GetStreamCount ( )
overridevirtual

! Called by Import.cpp

Returns
number of readable audio streams in the file

Implements ImportFileHandle.

Definition at line 889 of file ImportGStreamer.cpp.

890 {
891  return mStreamInfo.size();
892 }

References mStreamInfo.

◆ GetStreamInfo()

const TranslatableStrings & GStreamerImportFileHandle::GetStreamInfo ( )
overridevirtual

! Called by Import.cpp

Returns
array of strings - descriptions of the streams

Implements ImportFileHandle.

Definition at line 897 of file ImportGStreamer.cpp.

898 {
899  return mStreamInfo;
900 }

References mStreamInfo.

◆ Import()

int GStreamerImportFileHandle::Import ( TrackFactory *  trackFactory,
TrackHolders outTracks,
Tags tags 
)
override

! Imports audio

Returns
import status (see Import.cpp)

Definition at line 1017 of file ImportGStreamer.cpp.

1020 {
1021  outTracks.clear();
1022 
1023  // Save track factory pointer
1024  mTrackFactory = trackFactory;
1025 
1026  // Create the progress dialog
1027  CreateProgress();
1028 
1029  // Block streams that are to be bypassed
1030  bool haveStreams = false;
1031  {
1032  g_mutex_locker locker{ mStreamsLock };
1033  for (guint i = 0; i < mStreams.size(); i++)
1034  {
1035  GStreamContext *c = mStreams[i].get();
1036 
1037  // Did the user choose to skip this stream?
1038  if (!c->mUse)
1039  {
1040  // Get the audioconvert sink pad and unlink
1041  {
1042  GstObjHandle<GstPad> convsink{ gst_element_get_static_pad(c->mConv, "sink") };
1043 
1044  {
1045  GstObjHandle<GstPad> convpeer{ gst_pad_get_peer(convsink.get()) };
1046  gst_pad_unlink(convpeer.get(), convsink.get());
1047  }
1048 
1049  // Set bitbucket callbacks so the prerolled sample won't get processed
1050  // when we change the state to PLAYING
1051  gst_app_sink_set_callbacks(GST_APP_SINK(c->mSink), &AppSinkBitBucket, this, NULL);
1052 
1053  // Set state to playing for conv and sink so EOS gets processed
1054  gst_element_set_state(c->mConv, GST_STATE_PLAYING);
1055  gst_element_set_state(c->mSink, GST_STATE_PLAYING);
1056 
1057  // Send an EOS event to the pad to force them to drain
1058  gst_pad_send_event(convsink.get(), gst_event_new_eos());
1059 
1060  // Resync state with pipeline
1061  gst_element_sync_state_with_parent(c->mConv);
1062  gst_element_sync_state_with_parent(c->mSink);
1063 
1064  // Done with the pad
1065  }
1066 
1067  // Unlink audioconvert and appsink
1068  gst_element_unlink(c->mConv, c->mSink);
1069 
1070  // Remove them from the bin
1071  gst_bin_remove_many(GST_BIN(mPipeline.get()), c->mConv, c->mSink, NULL);
1072 
1073  // All done with them
1074  c->mConv = NULL;
1075  c->mSink = NULL;
1076 
1077  continue;
1078  }
1079 
1080  // We have a stream to process
1081  haveStreams = true;
1082  }
1083  }
1084 
1085  // Can't do much if we don't have any streams to process
1086  if (!haveStreams)
1087  {
1089  XO("File doesn't contain any audio streams."),
1090  XO("GStreamer Importer"));
1091  return ProgressResult::Failed;
1092  }
1093 
1094  // Get the ball rolling...
1095  GstStateChangeReturn state = gst_element_set_state(mPipeline.get(), GST_STATE_PLAYING);
1096  if (state == GST_STATE_CHANGE_FAILURE)
1097  {
1099  XO("Unable to import file, state change failed."),
1100  XO("GStreamer Importer"));
1101  return ProgressResult::Failed;
1102  }
1103 
1104  // Get the duration of the stream
1105  gint64 duration;
1106  gst_element_query_duration(mPipeline.get(), GST_FORMAT_TIME, &duration);
1107 
1108  // Handle bus messages and update progress while files is importing
1109  bool success = true;
1110  int updateResult = ProgressResult::Success;
1111  while (ProcessBusMessage(success) && success && updateResult == ProgressResult::Success)
1112  {
1113  gint64 position;
1114 
1115  // Update progress indicator and give user chance to abort
1116  if (gst_element_query_position(mPipeline.get(), GST_FORMAT_TIME, &position))
1117  {
1118  updateResult = mProgress->Update((wxLongLong_t) position,
1119  (wxLongLong_t) duration);
1120  }
1121  }
1122 
1123  // Disable pipeline
1124  gst_element_set_state(mPipeline.get(), GST_STATE_NULL);
1125 
1126  // Something bad happened
1127  if (!success || updateResult == ProgressResult::Failed || updateResult == ProgressResult::Cancelled)
1128  {
1129  return updateResult;
1130  }
1131 
1132  // Grab the streams lock
1133  g_mutex_locker locker{ mStreamsLock };
1134 
1135  // Copy audio from mChannels to newly created tracks (destroying mChannels in process)
1136  int trackindex = 0;
1137  for (guint s = 0; s < mStreams.size(); s++)
1138  {
1139  GStreamContext *c = mStreams[s].get();
1140  if (c->mNumChannels)
1141  {
1142  for (int ch = 0; ch < c->mNumChannels; ch++)
1143  c->mChannels[ch]->Flush();
1144  outTracks.push_back(std::move(c->mChannels));
1145  }
1146  }
1147 
1148  // Set any tags found in the stream
1149  *tags = mTags;
1150 
1151  return updateResult;
1152 }

References AppSinkBitBucket, AudacityMessageBox(), RefreshCode::Cancelled, ImportFileHandle::CreateProgress(), GStreamContext::mChannels, GStreamContext::mConv, GStreamContext::mNumChannels, mPipeline, ImportFileHandle::mProgress, GStreamContext::mSink, mStreams, mStreamsLock, mTags, mTrackFactory, GStreamContext::mUse, ProcessBusMessage(), BasicUI::Success, and XO.

Here is the call graph for this function:

◆ Init()

bool GStreamerImportFileHandle::Init ( )

! Format initialization

Returns
true if successful, false otherwise

Definition at line 918 of file ImportGStreamer.cpp.

919 {
920  // Create a URI from the filename
921  mUri.reset(g_strdup_printf("file:///%s", mFilename.ToUTF8().data()));
922  if (!mUri)
923  {
924  wxLogMessage(wxT("GStreamerImport couldn't create URI"));
925  return false;
926  }
927 
928  // Create a pipeline
929  mPipeline.reset(gst_pipeline_new("pipeline"));
930 
931  // Get its bus
932  mBus.reset(gst_pipeline_get_bus(GST_PIPELINE(mPipeline.get())));
933 
934  // Create uridecodebin and set up signal handlers
935  mDec = gst_element_factory_make("uridecodebin", "decoder");
936  g_signal_connect(mDec, "autoplug-select", G_CALLBACK(GStreamerAutoplugSelectCallback), (gpointer) this);
937  g_signal_connect(mDec, "pad-added", G_CALLBACK(GStreamerPadAddedCallback), (gpointer) this);
938  g_signal_connect(mDec, "pad-removed", G_CALLBACK(GStreamerPadRemovedCallback), (gpointer) this);
939 
940  // Set the URI
941  g_object_set(G_OBJECT(mDec), "uri", mUri, NULL);
942 
943  // Add the decoder to the pipeline
944  if (!gst_bin_add(GST_BIN(mPipeline.get()), mDec))
945  {
947  XO("Unable to add decoder to pipeline"),
948  XO("GStreamer Importer"));
949 
950  // Cleanup expected to occur in destructor
951  return false;
952  }
953 
954  // Run the pipeline
955  GstStateChangeReturn state = gst_element_set_state(mPipeline.get(), GST_STATE_PAUSED);
956  if (state == GST_STATE_CHANGE_FAILURE)
957  {
959  XO("Unable to set stream state to paused."),
960  XO("GStreamer Importer"));
961  return false;
962  }
963 
964  // Collect info while the stream is prerolled
965  //
966  // Unfortunately, for some files this may cause a slight "pause" in the GUI
967  // without a progress dialog appearing. Not much can be done about it other
968  // than throwing up an additional progress dialog and displaying two dialogs
969  // may be confusing to the users.
970 
971  // Process messages until we get an error or the ASYNC_DONE message is received
972  bool success;
973  while (ProcessBusMessage(success) && success)
974  {
975  // Give wxWidgets a chance to do housekeeping
976  wxSafeYield();
977  }
978 
979  // Build the stream info array
980  g_mutex_locker locker{ mStreamsLock };
981  for (guint i = 0; i < mStreams.size(); i++)
982  {
983  GStreamContext *c = mStreams[i].get();
984 
985  // Create stream info string
986  auto strinfo = XO("Index[%02d], Type[%s], Channels[%d], Rate[%d]")
987  .Format(
988  (unsigned int) i,
989  wxString::FromUTF8(c->mType.get()),
990  (int) c->mNumChannels,
991  (int) c->mSampleRate );
992  mStreamInfo.push_back(strinfo);
993  }
994 
995  return success;
996 }

References AudacityMessageBox(), GStreamerAutoplugSelectCallback(), GStreamerPadAddedCallback(), GStreamerPadRemovedCallback(), mBus, mDec, ImportFileHandle::mFilename, GStreamContext::mNumChannels, mPipeline, GStreamContext::mSampleRate, mStreamInfo, mStreams, mStreamsLock, GStreamContext::mType, mUri, ProcessBusMessage(), and XO.

Here is the call graph for this function:

◆ OnNewSample()

void GStreamerImportFileHandle::OnNewSample ( GStreamContext c,
GstSample *  sample 
)

! Called when a NEW samples are queued

Parameters
c- stream context
sample- gstreamer sample

Definition at line 730 of file ImportGStreamer.cpp.

731 {
732  // Allocate NEW tracks
733  //
734  // It is done here because, at least in the case of chained oggs,
735  // not all streams are known ahead of time.
736  if (c->mChannels.empty())
737  {
738  // Get the sample format...no need to release caps or structure
739  GstCaps *caps = gst_sample_get_caps(sample);
740  GstStructure *str = gst_caps_get_structure(caps, 0);
741  const gchar *fmt = gst_structure_get_string(str, "format");
742  if (!fmt)
743  {
744  WARN(mPipeline.get(), ("OnNewSample: missing audio format"));
745  return;
746  }
747 
748  // Determinate sample format based on negotiated format
749  if (strcmp(fmt, GST_AUDIO_NE(S16)) == 0)
750  {
751  c->mFmt = int16Sample;
752  }
753  else if (strcmp(fmt, GST_AUDIO_NE(S24_32)) == 0)
754  {
755  c->mFmt = int24Sample;
756  }
757  else if (strcmp(fmt, GST_AUDIO_NE(F32)) == 0)
758  {
759  c->mFmt = floatSample;
760  }
761  else
762  {
763  // This shouldn't really happen since audioconvert will only give us
764  // the formats we said we could handle.
765  WARN(mPipeline.get(), ("OnNewSample: unrecognized sample format %s", fmt));
766  return;
767  }
768 
769  // Allocate the track array
770  c->mChannels.resize(c->mNumChannels);
771  if (c->mChannels.size() != c->mNumChannels)
772  {
773  WARN(mPipeline.get(), ("OnNewSample: unable to allocate track array"));
774  return;
775  }
776 
777  // Allocate all channels
778  for (int ch = 0; ch < c->mNumChannels; ch++)
779  {
780  // Create a track
781  c->mChannels[ch] = mTrackFactory->NewWaveTrack(c->mFmt, c->mSampleRate);
782  if (!c->mChannels[ch])
783  {
784  WARN(mPipeline.get(), ("OnNewSample: unable to create track"));
785  return;
786  }
787  }
788  }
789 
790  // Get the buffer for the sample...no need to release
791  GstBuffer *buffer = gst_sample_get_buffer(sample);
792  if (!buffer)
793  {
794  // No buffer...not sure if this is an error or not,
795  // but we can't do anything else, so just bail silently.
796  return;
797  }
798 
799  // Map the buffer
800  GstMapInfo info;
801  if (!gst_buffer_map(buffer, &info, GST_MAP_READ))
802  {
803  WARN(mPipeline.get(), ("OnNewSample: mapping buffer failed"));
804  return;
805  }
806  auto cleanup = finally([&]{
807  // Release buffer
808  gst_buffer_unmap(buffer, &info);
809  });
810 
811  // Cache a few items
812  auto nChannels = c->mNumChannels;
813  sampleFormat fmt = c->mFmt;
814  samplePtr data = (samplePtr) info.data;
815  size_t samples = info.size / nChannels / SAMPLE_SIZE(fmt);
816 
817  // Add sample data to tracks...depends on interleaved src data
818  for (int chn = 0; chn < nChannels; chn++)
819  {
820  // Append one channel
821  c->mChannels[chn]->Append(data,
822  fmt,
823  samples,
824  nChannels);
825 
826  // Bump src to next channel
827  data += SAMPLE_SIZE(fmt);
828  }
829 
830  return;
831 }

References floatSample, int16Sample, int24Sample, GStreamContext::mChannels, GStreamContext::mFmt, GStreamContext::mNumChannels, mPipeline, GStreamContext::mSampleRate, mTrackFactory, SAMPLE_SIZE, str, and WARN.

Referenced by GStreamerNewSample().

Here is the caller graph for this function:

◆ OnPadAdded()

void GStreamerImportFileHandle::OnPadAdded ( GstPad *  pad)

! Called when a pad-added signal comes in from UriDecodeBin

Parameters
pad- source pad of uridecodebin that will not be serving any data

Definition at line 535 of file ImportGStreamer.cpp.

536 {
537  GStreamContext *c{};
538 
539  {
540  // Retrieve the stream caps...skip stream if unavailable
541  GstCaps *caps = gst_pad_get_current_caps(pad);
542  GstCapsHandle handle{ caps };
543 
544  if (!caps)
545  {
546  WARN(mPipeline.get(), ("OnPadAdded: unable to retrieve stream caps"));
547  return;
548  }
549 
550  // Get the caps structure...no need to release
551  GstStructure *str = gst_caps_get_structure(caps, 0);
552  if (!str)
553  {
554  WARN(mPipeline.get(), ("OnPadAdded: unable to retrieve caps structure"));
555  return;
556  }
557 
558  // Only accept audio streams...no need to release
559  const gchar *name = gst_structure_get_name(str);
560  if (!g_strrstr(name, "audio"))
561  {
562  WARN(mPipeline.get(), ("OnPadAdded: bypassing '%s' stream", name));
563  return;
564  }
565 
566  {
567  // Allocate a NEW stream context
568  auto uc = std::make_unique<GStreamContext>();
569  c = uc.get();
570  if (!c)
571  {
572  WARN(mPipeline.get(), ("OnPadAdded: unable to allocate stream context"));
573  return;
574  }
575 
576  // Set initial state
577  c->mUse = true;
578 
579  // Always add it to the context list to keep the number of contexts
580  // in sync with the number of streams
582  // Pass the buck from uc
583  mStreams.push_back(std::move(uc));
584  }
585 
586  c->mPipeline = mPipeline.get();
587 
588  // Need pointer to context during pad removal (pad-remove signal)
589  SETCTX(pad, c);
590 
591  // Save the stream's start time and duration
592  gst_pad_query_position(pad, GST_FORMAT_TIME, &c->mPosition);
593  gst_pad_query_duration(pad, GST_FORMAT_TIME, &c->mDuration);
594 
595  // Retrieve the number of channels and validate
596  gint channels = -1;
597  gst_structure_get_int(str, "channels", &channels);
598  if (channels <= 0)
599  {
600  WARN(mPipeline.get(), ("OnPadAdded: channel count is invalid %d", channels));
601  return;
602  }
603  c->mNumChannels = channels;
604 
605  // Retrieve the sample rate and validate
606  gint rate = -1;
607  gst_structure_get_int(str, "rate", &rate);
608  if (rate <= 0)
609  {
610  WARN(mPipeline.get(), ("OnPadAdded: sample rate is invalid %d", rate));
611  return;
612  }
613  c->mSampleRate = (double)rate;
614 
615  c->mType.reset(g_strdup(name));
616  if (!c->mType)
617  {
618  WARN(mPipeline.get(), ("OnPadAdded: unable to allocate audio type"));
619  return;
620  }
621 
622  // Done with capabilities
623  }
624 
625  // Create audioconvert element
626  c->mConv = gst_element_factory_make("audioconvert", NULL);
627  if (!c->mConv)
628  {
629  WARN(mPipeline.get(), ("OnPadAdded: failed to create audioconvert element"));
630  return;
631  }
632 
633  // Create appsink element
634  c->mSink = gst_element_factory_make("appsink", NULL);
635  if (!c->mSink)
636  {
637  WARN(mPipeline.get(), ("OnPadAdded: failed to create appsink element"));
638  return;
639  }
640  SETCTX(c->mSink, c);
641 
642  // Set the appsink callbacks and add the context pointer
643  gst_app_sink_set_callbacks(GST_APP_SINK(c->mSink), &AppSinkCallbacks, this, NULL);
644 
645  {
646  // Set the capabilities that we desire
647  GstCaps *caps = gst_static_caps_get(&supportedCaps);
648  GstCapsHandle handle{ caps };
649  if (!caps)
650  {
651  WARN(mPipeline.get(), ("OnPadAdded: failed to create static caps"));
652  return;
653  }
654  gst_app_sink_set_caps(GST_APP_SINK(c->mSink), caps);
655  }
656 
657  // Do not sync to the clock...process as quickly as possible
658  gst_base_sink_set_sync(GST_BASE_SINK(c->mSink), FALSE);
659 
660  // Don't drop buffers...allow queue to build unfettered
661  gst_app_sink_set_drop(GST_APP_SINK(c->mSink), FALSE);
662 
663  // Add both elements to the pipeline
664  gst_bin_add_many(GST_BIN(mPipeline.get()), c->mConv, c->mSink, NULL);
665 
666  // Link them together
667  if (!gst_element_link(c->mConv, c->mSink))
668  {
669  WARN(mPipeline.get(), ("OnPadAdded: failed to link audioconvert and appsink"));
670  return;
671  }
672 
673  // Link the audiconvert sink pad to the src pad
674  GstPadLinkReturn ret = GST_PAD_LINK_OK;
675  {
676  GstObjHandle<GstPad> convsink{ gst_element_get_static_pad(c->mConv, "sink") };
677  if (convsink)
678  ret = gst_pad_link(pad, convsink.get());
679  if (!convsink || ret != GST_PAD_LINK_OK)
680  {
681  WARN(mPipeline.get(), ("OnPadAdded: failed to link uridecodebin to audioconvert - %d", ret));
682  return;
683  }
684  }
685 
686  // Synchronize audioconvert state with parent
687  if (!gst_element_sync_state_with_parent(c->mConv))
688  {
689  WARN(mPipeline.get(), ("OnPadAdded: unable to sync audioconvert state"));
690  return;
691  }
692 
693  // Synchronize appsink state with parent
694  if (!gst_element_sync_state_with_parent(c->mSink))
695  {
696  WARN(mPipeline.get(), ("OnPadAdded: unable to sync appaink state"));
697  return;
698  }
699 
700  return;
701 }

References AppSinkCallbacks, mPipeline, mStreams, mStreamsLock, name, SETCTX, str, supportedCaps, and WARN.

◆ OnPadRemoved()

void GStreamerImportFileHandle::OnPadRemoved ( GstPad *  pad)

! Called when a pad-removed signal comes in from UriDecodeBin

Parameters
pad- source pad of uridecodebin that will not be serving any data

Definition at line 706 of file ImportGStreamer.cpp.

707 {
708  GStreamContext *c = GETCTX(pad);
709 
710  // Set audioconvert and appsink states to NULL
711  gst_element_set_state(c->mSink, GST_STATE_NULL);
712  gst_element_set_state(c->mConv, GST_STATE_NULL);
713 
714  // Unlink audioconvert -> appsink
715  gst_element_unlink(c->mConv, c->mSink);
716 
717  // Remove the pads from the pipeilne
718  gst_bin_remove_many(GST_BIN(mPipeline.get()), c->mConv, c->mSink, NULL);
719 
720  // And reset context
721  c->mConv = NULL;
722  c->mSink = NULL;
723 
724  return;
725 }

References GETCTX, GStreamContext::mConv, mPipeline, and GStreamContext::mSink.

◆ OnTag()

void GStreamerImportFileHandle::OnTag ( GstAppSink *  appsink,
GstTagList *  tags 
)

! Called when a tag message comes in from the appsink

Parameters
appsink- Specific sink that received the message
tags- List of tags

Definition at line 1314 of file ImportGStreamer.cpp.

1315 {
1316  // Collect all of the associates tags
1317  for (guint i = 0, icnt = gst_tag_list_n_tags(tags); i < icnt; i++)
1318  {
1319  wxString string;
1320 
1321  // Get tag name...should always succeed...no need to release
1322  const gchar *name = gst_tag_list_nth_tag_name(tags, i);
1323  if (!name)
1324  {
1325  continue;
1326  }
1327 
1328  // For each tag, determine its type and retrieve if possible
1329  for (guint j = 0, jcnt = gst_tag_list_get_tag_size(tags, name); j < jcnt; j++)
1330  {
1331  const GValue *val;
1332 
1333  val = gst_tag_list_get_value_index(tags, name, j);
1334 
1335  if (G_VALUE_HOLDS_STRING(val))
1336  {
1337  string = wxString::FromUTF8(g_value_get_string(val));
1338  }
1339  else if (G_VALUE_HOLDS_UINT(val))
1340  {
1341  string.Printf(wxT("%u"), (unsigned int) g_value_get_uint(val));
1342  }
1343  else if (G_VALUE_HOLDS_DOUBLE(val))
1344  {
1345  string.Printf(wxT("%g"), g_value_get_double(val));
1346  }
1347  else if (G_VALUE_HOLDS_BOOLEAN(val))
1348  {
1349  string = g_value_get_boolean(val) ? wxT("true") : wxT("false");
1350  }
1351  else if (GST_VALUE_HOLDS_DATE_TIME(val))
1352  {
1353  GstDateTime *dt = (GstDateTime *) g_value_get_boxed(val);
1354  GstString str{ gst_date_time_to_iso8601_string(dt) };
1355  string = wxString::FromUTF8(str.get());
1356  }
1357  else if (G_VALUE_HOLDS(val, G_TYPE_DATE))
1358  {
1359  GstString str{ gst_value_serialize(val) };
1360  string = wxString::FromUTF8(str.get());
1361  }
1362  else
1363  {
1364  wxLogMessage(wxT("Tag %s has unhandled type: %s"),
1365  wxString::FromUTF8(name),
1366  wxString::FromUTF8(G_VALUE_TYPE_NAME(val)));
1367  continue;
1368  }
1369 
1370  // Translate known tag names
1371  wxString tag;
1372  if (strcmp(name, GST_TAG_TITLE) == 0)
1373  {
1374  tag = TAG_TITLE;
1375  }
1376  else if (strcmp(name, GST_TAG_ARTIST) == 0)
1377  {
1378  tag = TAG_ARTIST;
1379  }
1380  else if (strcmp(name, GST_TAG_ALBUM) == 0)
1381  {
1382  tag = TAG_ALBUM;
1383  }
1384  else if (strcmp(name, GST_TAG_TRACK_NUMBER) == 0)
1385  {
1386  tag = TAG_TRACK;
1387  }
1388  else if (strcmp(name, GST_TAG_DATE) == 0)
1389  {
1390  tag = TAG_YEAR;
1391  }
1392  else if (strcmp(name, GST_TAG_GENRE) == 0)
1393  {
1394  tag = TAG_GENRE;
1395  }
1396  else if (strcmp(name, GST_TAG_COMMENT) == 0)
1397  {
1398  tag = TAG_COMMENTS;
1399  }
1400  else
1401  {
1402  tag = wxString::FromUTF8(name);
1403  }
1404 
1405  if (jcnt > 1)
1406  {
1407  tag.Printf(wxT("%s:%d"), tag, j);
1408  }
1409 
1410  // Store the tag
1411  mTags.SetTag(tag, string);
1412  }
1413  }
1414 }

References mTags, name, Tags::SetTag(), str, TAG_ALBUM, TAG_ARTIST, TAG_COMMENTS, TAG_GENRE, TAG_TITLE, TAG_TRACK, and TAG_YEAR.

Referenced by ProcessBusMessage().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ProcessBusMessage()

bool GStreamerImportFileHandle::ProcessBusMessage ( bool &  success)

! Called when a message comes through GStreamer message bus

Parameters
success- will be set to true if successful
Returns
true if the loop should be terminated

Definition at line 1163 of file ImportGStreamer.cpp.

1164 {
1165  bool cont = true;
1166 
1167  // Default to no errors
1168  success = true;
1169 
1170  // Get the next message
1171  std::unique_ptr < GstMessage, Deleter < GstMessage, GstMessageUnref > >
1172  msg{ gst_bus_timed_pop(mBus.get(), 100 * GST_MSECOND) };
1173 
1174  if (!msg)
1175  {
1176  // Timed out...not an error
1177  return cont;
1178  }
1179 
1180 #if defined(_DEBUG)
1181  {
1182  GstString objname;
1183  if (msg->src != NULL)
1184  {
1185  objname.reset(gst_object_get_name(msg->src));
1186  }
1187 
1188  wxLogMessage(wxT("GStreamer: Got %s%s%s"),
1189  wxString::FromUTF8(GST_MESSAGE_TYPE_NAME(msg.get())),
1190  objname ? wxT(" from ") : wxT(""),
1191  objname ? wxString::FromUTF8(objname.get()) : wxT(""));
1192  }
1193 #endif
1194 
1195  // Handle based on message type
1196  switch (GST_MESSAGE_TYPE(msg.get()))
1197  {
1198  // Handle error message from gstreamer
1199  case GST_MESSAGE_ERROR:
1200  {
1201  GErrorHandle err;
1202  GstString debug;
1203 
1204  GstMessageParse(gst_message_parse_error, msg.get(), err, debug);
1205  if (err)
1206  {
1207  wxString m;
1208 
1209  m.Printf(wxT("%s%s%s"),
1210  wxString::FromUTF8(err.get()->message),
1211  debug ? wxT("\n") : wxT(""),
1212  debug ? wxString::FromUTF8(debug.get()) : wxT(""));
1213  auto msg = XO("GStreamer Error: %s").Format( m );
1214 #if defined(_DEBUG)
1215  AudacityMessageBox( msg );
1216 #else
1217  wxLogMessage( msg.Debug() );
1218 #endif
1219  }
1220 
1221  success = false;
1222  cont = false;
1223  }
1224  break;
1225 
1226  // Handle warning message from gstreamer
1227  case GST_MESSAGE_WARNING:
1228  {
1229  GErrorHandle err;
1230  GstString debug;
1231  GstMessageParse(gst_message_parse_warning, msg.get(), err, debug);
1232 
1233  if (err)
1234  {
1235  wxLogMessage(wxT("GStreamer Warning: %s%s%s"),
1236  wxString::FromUTF8(err.get()->message),
1237  debug ? wxT("\n") : wxT(""),
1238  debug ? wxString::FromUTF8(debug.get()) : wxT(""));
1239  }
1240  }
1241  break;
1242 
1243  // Handle warning message from gstreamer
1244  case GST_MESSAGE_INFO:
1245  {
1246  GErrorHandle err;
1247  GstString debug;
1248 
1249  GstMessageParse(gst_message_parse_info, msg.get(), err, debug);
1250  if (err)
1251  {
1252  wxLogMessage(wxT("GStreamer Info: %s%s%s"),
1253  wxString::FromUTF8(err.get()->message),
1254  debug ? wxT("\n") : wxT(""),
1255  debug ? wxString::FromUTF8(debug.get()) : wxT(""));
1256  }
1257  }
1258  break;
1259 
1260  // Handle metadata tags
1261  case GST_MESSAGE_TAG:
1262  {
1263  GstTagList *tags = NULL;
1264  auto cleanup = finally([&]{
1265  // Done with list
1266  if(tags) gst_tag_list_unref(tags);
1267  });
1268 
1269  // Retrieve tag list from message...just ignore failure
1270  gst_message_parse_tag(msg.get(), &tags);
1271  if (tags)
1272  {
1273  // Go process the list
1274  OnTag(GST_APP_SINK(GST_MESSAGE_SRC(msg.get())), tags);
1275  }
1276  }
1277  break;
1278 
1279  // Pre-roll is done...will happen for each group
1280  // (like with chained OGG files)
1281  case GST_MESSAGE_ASYNC_DONE:
1282  {
1283  // If this is the first async-done message, then tell
1284  // caller to end loop, but leave it active so that
1285  // gstreamer threads can still queue up.
1286  //
1287  // We'll receive multiple async-done messages for chained
1288  // ogg files, so ignore the message the 2nd and subsequent
1289  // occurrences.
1290  if (!mAsyncDone)
1291  {
1292  cont = false;
1293  mAsyncDone = true;
1294  }
1295 
1296  }
1297  break;
1298 
1299  // End of the stream (and all sub-streams)
1300  case GST_MESSAGE_EOS:
1301  {
1302  // Terminate loop
1303  cont = false;
1304  }
1305  break;
1306  }
1307 
1308  return cont;
1309 }

References AudacityMessageBox(), GstMessageParse(), mAsyncDone, mBus, OnTag(), and XO.

Referenced by Import(), and Init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetStreamUsage()

void GStreamerImportFileHandle::SetStreamUsage ( wxInt32  index,
bool  use 
)
overridevirtual

! Called by Import.cpp

Parameters
index- index of the stream in mStreamInfo and mStreams arrays
use- true if this stream should be imported, false otherwise

Implements ImportFileHandle.

Definition at line 905 of file ImportGStreamer.cpp.

906 {
907  g_mutex_locker locker{ mStreamsLock };
908  if ((guint) index < mStreams.size())
909  {
910  GStreamContext *c = mStreams[index].get();
911  c->mUse = use;
912  }
913 }

References mStreams, mStreamsLock, and GStreamContext::mUse.

Member Data Documentation

◆ mAsyncDone

bool GStreamerImportFileHandle::mAsyncDone
private

true = 1st async-done message received

Definition at line 226 of file ImportGStreamer.cpp.

Referenced by GStreamerImportFileHandle(), and ProcessBusMessage().

◆ mBus

GstObjHandle<GstBus> GStreamerImportFileHandle::mBus
private

Message bus.

Definition at line 224 of file ImportGStreamer.cpp.

Referenced by Init(), and ProcessBusMessage().

◆ mDec

GstElement* GStreamerImportFileHandle::mDec
private

uridecodebin element

Definition at line 225 of file ImportGStreamer.cpp.

Referenced by GStreamerImportFileHandle(), Init(), and ~GStreamerImportFileHandle().

◆ mPipeline

GstObjHandle<GstElement> GStreamerImportFileHandle::mPipeline
private

GStreamer pipeline.

Definition at line 223 of file ImportGStreamer.cpp.

Referenced by Import(), Init(), OnNewSample(), OnPadAdded(), OnPadRemoved(), and ~GStreamerImportFileHandle().

◆ mStreamInfo

TranslatableStrings GStreamerImportFileHandle::mStreamInfo
private

Array of stream descriptions. Length is the same as mStreams.

Definition at line 218 of file ImportGStreamer.cpp.

Referenced by GetStreamCount(), GetStreamInfo(), and Init().

◆ mStreams

std::vector<std::unique_ptr<GStreamContext> > GStreamerImportFileHandle::mStreams
private

Array of pointers to stream contexts.

Definition at line 229 of file ImportGStreamer.cpp.

Referenced by Import(), Init(), OnPadAdded(), SetStreamUsage(), and ~GStreamerImportFileHandle().

◆ mStreamsLock

GMutex GStreamerImportFileHandle::mStreamsLock
private

Mutex protecting the mStreams array.

Definition at line 228 of file ImportGStreamer.cpp.

Referenced by GStreamerImportFileHandle(), Import(), Init(), OnPadAdded(), SetStreamUsage(), and ~GStreamerImportFileHandle().

◆ mTags

Tags GStreamerImportFileHandle::mTags
private

Tags to be passed back to Audacity.

Definition at line 219 of file ImportGStreamer.cpp.

Referenced by Import(), and OnTag().

◆ mTrackFactory

TrackFactory* GStreamerImportFileHandle::mTrackFactory
private

Factory to create tracks when samples arrive.

Definition at line 220 of file ImportGStreamer.cpp.

Referenced by GStreamerImportFileHandle(), Import(), and OnNewSample().

◆ mUri

GstString GStreamerImportFileHandle::mUri
private

URI of file.

Definition at line 222 of file ImportGStreamer.cpp.

Referenced by Init().


The documentation for this class was generated from the following file:
supportedCaps
static GstStaticCaps supportedCaps
Definition: ImportGStreamer.cpp:74
GStreamContext::mNumChannels
unsigned mNumChannels
Definition: ImportGStreamer.cpp:128
BasicUI::ProgressResult::Success
@ Success
GstCapsHandle
std::unique_ptr< GstCaps, Deleter< GstCaps, GstCapsUnref > > GstCapsHandle
Definition: ImportGStreamer.cpp:530
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Definition: AudacityMessageBox.cpp:17
str
#define str(a)
Definition: DBConnection.cpp:30
GStreamerImportFileHandle::mUri
GstString mUri
URI of file.
Definition: ImportGStreamer.cpp:222
TAG_TRACK
#define TAG_TRACK
Definition: Tags.h:63
GStreamerImportFileHandle::mAsyncDone
bool mAsyncDone
true = 1st async-done message received
Definition: ImportGStreamer.cpp:226
GStreamerImportFileHandle::mBus
GstObjHandle< GstBus > mBus
Message bus.
Definition: ImportGStreamer.cpp:224
SAMPLE_SIZE
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:44
GStreamContext::mType
GstString mType
Definition: ImportGStreamer.cpp:130
RefreshCode::Cancelled
@ Cancelled
Definition: RefreshCode.h:23
XO
#define XO(s)
Definition: Internat.h:31
GStreamContext
Definition: ImportGStreamer.cpp:123
AppSinkBitBucket
static GstAppSinkCallbacks AppSinkBitBucket
Definition: ImportGStreamer.cpp:522
int24Sample
@ int24Sample
Definition: SampleFormat.h:33
GStreamerPadRemovedCallback
static void GStreamerPadRemovedCallback(GstElement *WXUNUSED(element), GstPad *pad, gpointer data)
Definition: ImportGStreamer.cpp:478
GStreamContext::mChannels
NewChannelGroup mChannels
Definition: ImportGStreamer.cpp:127
GstObjHandle
std::unique_ptr< T, Deleter< void, gst_object_unref > > GstObjHandle
Definition: ImportGStreamer.cpp:155
ImportFileHandle::mProgress
std::unique_ptr< ProgressDialog > mProgress
Definition: ImportPlugin.h:159
GstString
std::unique_ptr< gchar, Deleter< void, g_free > > GstString
Definition: ImportGStreamer.cpp:108
floatSample
@ floatSample
Definition: SampleFormat.h:34
GErrorHandle
std::unique_ptr< GError, Deleter< GError, g_error_free > > GErrorHandle
Definition: ImportGStreamer.cpp:109
ImportFileHandle::ImportFileHandle
ImportFileHandle(const FilePath &filename)
Definition: ImportPlugin.cpp:36
ImportFileHandle::CreateProgress
void CreateProgress()
Definition: ImportPlugin.cpp:45
GStreamerImportFileHandle::ProcessBusMessage
bool ProcessBusMessage(bool &success)
Definition: ImportGStreamer.cpp:1163
GETCTX
#define GETCTX(o)
Definition: ImportGStreamer.cpp:61
Tags::SetTag
void SetTag(const wxString &name, const wxString &value, const bool bSpecialTag=false)
Definition: Tags.cpp:486
GStreamerAutoplugSelectCallback
static gint GStreamerAutoplugSelectCallback(GstElement *WXUNUSED(element), GstPad *WXUNUSED(pad), GstCaps *WXUNUSED(caps), GstElementFactory *factory, gpointer WXUNUSED(data))
Definition: ImportGStreamer.cpp:445
AppSinkCallbacks
static GstAppSinkCallbacks AppSinkCallbacks
Definition: ImportGStreamer.cpp:515
int16Sample
@ int16Sample
Definition: SampleFormat.h:32
GStreamerPadAddedCallback
static void GStreamerPadAddedCallback(GstElement *WXUNUSED(element), GstPad *pad, gpointer data)
Definition: ImportGStreamer.cpp:466
name
const TranslatableString name
Definition: Distortion.cpp:98
GStreamContext::mConv
GstElement * mConv
Definition: ImportGStreamer.cpp:124
TAG_GENRE
#define TAG_GENRE
Definition: Tags.h:65
ImportFileHandle::mFilename
FilePath mFilename
Definition: ImportPlugin.h:158
TAG_YEAR
#define TAG_YEAR
Definition: Tags.h:64
GstMessageParse
void GstMessageParse(ParseFn fn, GstMessage *msg, GErrorHandle &err, GstString &debug)
Definition: ImportGStreamer.cpp:112
GStreamerImportFileHandle::mPipeline
GstObjHandle< GstElement > mPipeline
GStreamer pipeline.
Definition: ImportGStreamer.cpp:223
sampleFormat
sampleFormat
Definition: SampleFormat.h:29
samplePtr
char * samplePtr
Definition: SampleFormat.h:49
GStreamerImportFileHandle::mDec
GstElement * mDec
uridecodebin element
Definition: ImportGStreamer.cpp:225
GStreamerImportFileHandle::mStreams
std::vector< std::unique_ptr< GStreamContext > > mStreams
Array of pointers to stream contexts.
Definition: ImportGStreamer.cpp:229
GStreamerImportFileHandle::mTags
Tags mTags
Tags to be passed back to Audacity.
Definition: ImportGStreamer.cpp:219
GStreamContext::mSink
GstElement * mSink
Definition: ImportGStreamer.cpp:125
g_mutex_locker
Definition: ImportGStreamer.cpp:86
DESC
#define DESC
Definition: ImportGStreamer.cpp:34
TAG_COMMENTS
#define TAG_COMMENTS
Definition: Tags.h:66
TAG_ARTIST
#define TAG_ARTIST
Definition: Tags.h:61
GStreamerImportFileHandle::mStreamsLock
GMutex mStreamsLock
Mutex protecting the mStreams array.
Definition: ImportGStreamer.cpp:228
GStreamerImportFileHandle::mTrackFactory
TrackFactory * mTrackFactory
Factory to create tracks when samples arrive.
Definition: ImportGStreamer.cpp:220
GStreamContext::mUse
bool mUse
Definition: ImportGStreamer.cpp:126
SETCTX
#define SETCTX(o, c)
Definition: ImportGStreamer.cpp:62
GStreamContext::mFmt
sampleFormat mFmt
Definition: ImportGStreamer.cpp:131
WARN
#define WARN(e, msg)
Definition: ImportGStreamer.cpp:63
GStreamerImportFileHandle::mStreamInfo
TranslatableStrings mStreamInfo
Array of stream descriptions. Length is the same as mStreams.
Definition: ImportGStreamer.cpp:218
TAG_TITLE
#define TAG_TITLE
Definition: Tags.h:60
GStreamerImportFileHandle::OnTag
void OnTag(GstAppSink *appsink, GstTagList *tags)
Definition: ImportGStreamer.cpp:1314
GStreamContext::mSampleRate
gdouble mSampleRate
Definition: ImportGStreamer.cpp:129
TAG_ALBUM
#define TAG_ALBUM
Definition: Tags.h:62