How do I remove subtitles from vlckit? - libvlc

I've written an app in swift that uses the vlckit framework. I have managed to get subtitles working by using
let url = URL(string: "file://Users/lonespeaker/test-subitltle.srt")
mediaPlayer.addPlaybackSlave(url, type: .subtitle, enforce: true)
but if the user wants to disable the subtitles after selecting one, I am stuck.
I have tried the following but had no luck
let url = URL(string: "")
mediaPlayer.addPlaybackSlave(url, type: .subtitle, enforce: true)
I've googled for an answer to remove the PlaybackSlave but there doesn't seem to be an API for it.
Here is an extract of my code :
guard let url = URL(string: "file://Users/lonespeaker/test-file.mkv") else { return }
let media = VLCMedia(url: url)
mediaPlayer.media = media
mediaPlayer.delegate = self
mediaPlayer.drawable = self.movieView
mediaPlayer.play()
then in the IBAction for disabling subtitles
#IBAction func disableSubtitles(_ sender: Any) {
let url = URL(string: "")
mediaPlayer.addPlaybackSlave(url, type: .subtitle, enforce: true)
}
I would have expected the PlaybackSlave to be changed/overwritten by the new URL and therefore disabling subtitles.
I would also expect an API call to disable a Playback Slave, but there doesn't appear to be one.
Anyone help? thanks.

Your approach is too complex. You can add an infinite number of playback slaves which indeed cannot be cleared using VLCKit at this point.
However, VLC will expose a list of available subtitles tracks during playback regardless of their source (you cannot differentiate between subtitles internal to the video and those added through an input slave), which you can iterate on and display to the user. Additionally, there is the player option to set the subtitles track ID you want to show. Those IDs can be queried from the API, too (note that the IDs can be 0, 1, 2, ... but it is perfectly legal to be 201, 4022, 8444, ..., too). However, to just disable, set this option to -1.

It looks like it's not exposed by vlckit, but libvlc does offer libvlc_media_slaves_clear.
You should try adding support for it in a local vlckit fork, and if it works, open a pull request. Other people might be interested.

Related

How do I query the vimeo api for a specific video title?

Hi I'm querying for a specific video by title - and at the moment I get mixed results.
my videos are all named with a consecutive number at the end ie ANDNOW2022_00112, ANDNOW2022_00113 etc
When I search /videos/?fields=uri,name&query=ANDNOW2022_00112 I get all of the videos returned
I've also tried the query_fields using
/me/videos?query_fields=title&sort=alphabetical&query=ANDNOW2022_00112
I just want the one I've searched for - or a no results returned.
At the moment I get all of the videos with AN2022 in the title/name. Now 'usually' the one I searched for is at the top of the list but not everytime.
Any tips appreciated.
Okay I'm not going mad :)
This is from Vimeo and is here for those with the same issue - basically to get t to work you need to understand that:
After speaking with our engineers, the current search capability are not "Exact" search.
When adding numbers or underscores the search is split into parts so "ANDNOW2022_00112" is transforming the query into the parts "andnow2022", "andnow", "2022", and "00112". So this is why your seeing these results. Our engineering team are in the process of improving the search capabilities and hope to provide a release in the near future.
Which means for now I'll have to rename my files.
Preface:
Vimeo does not currently offer an API endpoint for exact title search — but even if it did — it's possible to upload multiple videos and assign them identical titles. There's no way to use the API to positively identify a video by title — this is why every uploaded video is assigned a unique ID.
Solution:
Because the API returns data which includes an array of video objects, you can solve this problem in the same way you'd solve any similar problem in JavaScript where you have to find an element in an array: Array.prototype.find()
Here's how you can apply it to your problem:
Query the API using the parameters you described in your question.
You might also be interested in using the sort and direction parameters for greater control over a deterministic sort order.
Find the first item in the returned array of video objects that match your expected text exactly, and return it (or undefined if it doesn't exist)
Here's a code example with some static data from the API that was used to search for the video Mercedes Benz from the user egarage — note that I've omitted quite a few (irrelevant) fields from the response in order to keep the example small:
// Mocking fetch for this example:
function fetch (_requestInfo, _init) {
const staticJson = `{"total":2,"page":1,"per_page":25,"paging":{"next":null,"previous":null,"first":"/users/egarage/videos?query_fields=title&query=Mercedes%20Benz&sort=alphabetical&direction=asc&page=1","last":"/users/egarage/videos?query_fields=title&query=Mercedes%20Benz&sort=alphabetical&direction=asc&page=1"},"data":[{"uri":"/videos/61310450","name":"50th Anniversary of the Pagoda SL -- Mercedes-Benz Classic Vehicles","description":"Penned by designer Paul Bracq, the W113 SL had big shoes to fill: it had the incredible task of succeeding the original and instantly iconic 300 SL Gullwing. But you can't copy a legend, so Bracq designed one of his own. Straight lines replaced curves and a low-slung roof was replaced by a high top design that gave the car its nickname: the Pagoda.\\n\\nMUSIC: Developer Over Time","type":"video","link":"https://vimeo.com/61310450"},{"uri":"/videos/55837293","name":"Mercedes Benz","description":"To celebrate Mercedes Benz 125th birthday, the 2011 Pebble Beach Concours d’Elegance showcased the models that trace the lineage to Benz and Daimler —particularly Mercedes-Benz. This tribute chronicled early racing greats, coachbuilt classics, and preservation cars. Produced in association with DriveCulture.","type":"video","link":"https://vimeo.com/55837293"}]}`;
return Promise.resolve(new Response(staticJson));
}
async function fetchVideoByTitle (token, userId, videoTitle) {
const url = new URL(`https://api.vimeo.com/users/${userId}/videos`);
url.searchParams.set("query_fields", "title");
url.searchParams.set("query", videoTitle);
url.searchParams.set("sort", "alphabetical");
url.searchParams.set("direction", "asc");
const headers = new Headers([
["Authorization", `Bearer ${token}`],
]);
const response = await fetch(url.href, {headers});
const parsedJson = await response.json();
// Find the video that matches (if it exists):
const maybeFirstVideoObj = parsedJson.data.find(video => video.name === videoTitle);
return maybeFirstVideoObj;
}
async function main () {
const video = await fetchVideoByTitle(
"YOU_ACTUAL_TOKEN",
"egarage",
"Mercedes Benz",
);
console.log(video); // {name: "Mercedes Benz", link: "https://vimeo.com/55837293", ...}
}
main();

How do I send metadata from ExoPlayer to bluetooth?

I'm trying to send fixed metadata through bluetooth on my radio app, basically I would put the radio name as title, and the radio slogan as subtitle, so there isn't anything dynamic involved.
I have tried searching for other answers on StackOverflow but they're related to ICY streams or getting the metadata from ExoPlayer itself.
The stream itself provides the metadata when listening directly through FM or a stream player (for example, VLC), but it fails to display when going through my app.
This is my code, from what I've managed to understand I should send the metadata inside the brackets after 'addMetadataOutput'.
extractorsFactory = new DefaultExtractorsFactory();
trackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
trackSelector = new DefaultTrackSelector(trackSelectionFactory);
defaultBandwidthMeter = new DefaultBandwidthMeter();
dataSourceFactory = new DefaultDataSourceFactory(this,
Util.getUserAgent(this, "mediaPlayerSample"), defaultBandwidthMeter);
mediaSource = new ExtractorMediaSource(Uri.parse("https://sr11.inmystream.it/proxy/radiocircuito29?mp=/stream"), dataSourceFactory, extractorsFactory, null, null);
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector);
player.addMetadataOutput();
There are lots of dependencies in this area, it's not just a case of sending values, you are going to need to handle notifications and media sessions.
For that, you are going to need some additional Exoplayer extensions. Specifically: MediaSessionCompat, MediaSessionConnector and connect them up to to your Exoplayer and NotificationManager.
mMediaSession = new MediaSessionCompat( this, Constants.PLAYBACK_CHANNEL_ID );
mPlayerNotificationManager.setMediaSessionToken( mMediaSession.getSessionToken() );
mMediaSession.setActive( true );
mMediaSessionConnector = new MediaSessionConnector( mMediaSession );
mMediaSessionConnector.setPlayer( mPlayer );
Once you have these, you also need to implement a DescriptionAdapter class
public class MyDescriptionAdater implements PlayerNotificationManager.MediaDescriptionAdapter
This will create the interface to populate with your static metadata. You then need to wire this up to you PlayerNotificationManager using setMediaDescriptionAdapter

How do I share an Audio File in an App using Swift 3?

Sharing an Audio File in Swift
How do I share an audio file which exists in my apps document directory to other apps?
To elaborate on this question, what I mean is when a user taps a share button in the app they should be able to email their recorded audio track to another person, or alternatively to be able to send it across to a range of other apps which can handle audio like perhaps soundcloud.
Researching the topic, I have found:
UIActivityViewController
UIDocumentInteractionController
Since my application makes an audio recording of a person's voice which they should be able to share, and despite searching through stack overflow, I have not been able to find a code example of how exactly this option can be implemented in a Swift app. Can I request suggestions and example code on how this may be accomplished. Many Thanks,
Swift 3.x:
let activityItem = URL.init(fileURLWithPath: Bundle.main.path(forResource: "fileName", ofType: "mp3")!)
let activityVC = UIActivityViewController(activityItems: [activityItem],applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = self.view
self.present(activityVC, animated: true, completion: nil)
My answer is using for doing this with UIDocumentInteractionController.
I begin by instantiating a UIDocumentInteractionController at the top of my class
var controller = UIDocumentInteractionController()
Then I link up an IBAction to a share button on my nib or Storyboard:
#IBAction func SHARE(_ sender: Any) {
let dirPath: String = NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask,
true)[0]
let recordingName = UserDefaults.standard.string(forKey: "recordingName")
let pathArray: [String] = [dirPath, recordingName!]
let filePathString: String = pathArray.joined(separator: "/")
controller = UIDocumentInteractionController(url: NSURL(fileURLWithPath: filePathString) as URL)
controller.presentOpenInMenu(from: CGRect.zero,
in: self.view,
animated: true)
}

Setting a model attribute to a value based on, but not equal to, the input in angular-formly

I'm trying to figure out how to parse a form entry to set the model attribute to something else; e.g., extracting the video ID of a youtube video from a URL input. Is there a way to use parsers/formatters (6.21 features?) to accomplish this easily? I hoped to find a good example for this, and maybe there is one somewhere, but perhaps this would make a good one if there's not.
Here is a working example of what I'm attempting to accomplish, but in multiple steps and without the use of parsers. Any help adapting the code to set model.videoID from a URL in a single step (or fewer than 3 steps, at least) would be very appreciated. Thank you for your help with this and my other past questions. :)
Wow, this was much easier than I expected to implement. Here is the modification of the JS Bin which uses parsers, recently added with angular-formly#6.21.0, to extract the video ID from a YouTube URL in one function. It also, conveniently, validates itself!
Here is the relevant code, to summarize:
{
key: 'vidid',
type: 'input',
parsers: [extractID],
templateOptions: {
label: 'YouTube Video',
placeholder: 'Insert video URL here'
},
...
function extractID(value) {
if (value != undefined || value != '') {
var regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/;
var match = value.match(regExp);
if (match && match[2].length == 11) {
return match[2];
}
}
};

How to get direct show fillter?

i am recording video from webcam using DirectshowLib2005.dll in C#.net..i have this code to startVideoRecoding as below..
try
{
IBaseFilter capFilter = null;
IBaseFilter asfWriter = null;
IFileSinkFilter pTmpSink = null;
ICaptureGraphBuilder2 captureGraph = null;
GetVideoDevice();
if (availableVideoInputDevices.Count > 0)
{
//
//init capture graph
//
graphBuilder = (IFilterGraph2)new FilterGraph();
captureGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
//
//sets filter object from graph
//
captureGraph.SetFiltergraph(graphBuilder);
//
//which device will use graph setting
//
graphBuilder.AddSourceFilterForMoniker(AvailableVideoInputDevices.First().Mon, null, AvailableVideoInputDevices.First().Name, out capFilter);
captureDeviceName = AvailableVideoInputDevices.First().Name;
//
//check saving path is exsist or not;if not then create
//
if (!Directory.Exists(ConstantHelper.RootDirectoryName + "\\Assets\\Video\\"))
{
Directory.CreateDirectory(ConstantHelper.RootDirectoryName + "\\Assets\\Video\\");
}
#region WMV
//
//sets output file name,and file type
//
captureGraph.SetOutputFileName(MediaSubType.Asf, ConstantHelper.RootDirectoryName + "\\Assets\\Video\\" + videoFilename + ".wmv", out asfWriter, out pTmpSink);
//
//configure which video setting is used by graph
//
IConfigAsfWriter lConfig = asfWriter as IConfigAsfWriter;
Guid asfFilter = new Guid("8C45B4C7-4AEB-4f78-A5EC-88420B9DADEF");
lConfig.ConfigureFilterUsingProfileGuid(asfFilter);
#endregion
//
//render the stram to output file using graph setting
//
captureGraph.RenderStream(null, null, capFilter, null, asfWriter);
m_mediaCtrl = graphBuilder as IMediaControl;
m_mediaCtrl.Run();
isVideoRecordingStarted = true;
VideoStarted(m_mediaCtrl, null);
}
else
{
isVideoRecordingStarted = false;
}
}
catch (Exception Ex)
{
ErrorLogging.WriteErrorLog(Ex);
}
if you observe this lines of code
//
//configure which video setting is used by graph
//
IConfigAsfWriter lConfig = asfWriter as IConfigAsfWriter;
Guid asfFilter = new Guid("8C45B4C7-4AEB-4f78-A5EC-88420B9DADEF");
lConfig.ConfigureFilterUsingProfileGuid(asfFilter);
it will apply video setting which is described on that GUID i got this GUID from file located at "C:\windows\WMSysPr9.prx"..
so my question is how create my own video setting with format,resolutions and all?
How to Record video using webcam in black and white mode or in grayscale?
so my question is how create my own video setting with format,resolutions and all?
GUID based profiles are deprecated, though you can still use them. You can build custom profile in code using WMCreateProfileManager and friends (you start with empty profile and add video and/or audio streams at your discretion). This is C++ API, and I suppose that WindowsMedia.NET, a sister project to DirectShowLib you are already using, provides you interface into .NET code.
Windows SDK WMGenProfile sample both shows how to build profile manually and provides you a tool to build it interactively and save into .PRX file you can use in your application.
$(WindowsSDK)\Samples\multimedia\windowsmediaformat\wmgenprofile
How to Record video using webcam in black and white mode or in grayscale?
The camera gives you a picture, then it goes through pipeline up to recording through certain processing. Ability to make it greyscale is not something inherent.
There are two things you might want to think of. First of all, if the camera is capable of stripping color information on capture, you can leverage this. Check it out - if its settings have Saturation slider, then you just put it input minimal value position and the camera gives you greyscale.
In code, you use IAMVideoProcAmp interface for this.
Another option, including if the camera is missing mentioned capability, is to apply post processing filter or effect that converts to greyscale. There is no stock solution for this, and otherwise there are several ways to achieve the effect:
use third party filter that strips color
export from DirectShow pipeline, convert data in code using Color Control Transform DSP (available starting Win Vista) or GDI functions
use Sample Grabber in the streaming pipeline and update image bits directly

Resources