HiI need to stream a video file and save it using LIBVLC. Here is what I have done so far:
libvlc_media_t* vlcMedia = nullptr;
libvlc_instance_t* vlcInstance = libvlc_new(0, nullptr);
vlcMedia = libvlc_media_new_location(vlcInstance, aUri);
if(nullptr != vlcMedia)
{
libvlc_media_player_t* vlcMediaPlayer = libvlc_media_player_new_from_media(vlcMedia);
if(nullptr != vlcMediaPlayer)
{
libvlc_media_release(vlcMedia);
libvlc_event_manager_t* vlcMediaManager = libvlc_media_player_event_manager(vlcMediaPlayer);
if(nullptr != vlcMediaManager)
libvlc_event_attach(vlcMediaManager, libvlc_MediaPlayerEndReached, OnStopped, this);
libvlc_media_player_set_hwnd(vlcMediaPlayer, Handle);
libvlc_media_player_play(vlcMediaPlayer);
}
}
This will connect to the remote media and starts playing the video. The question is how do I direct it to save the video? I could not find the API call for that.
Thank youSam
Thanks to #mtz the solution is to add:
libvlc_media_add_option(vlcMedia,":sout=#duplicate{dst=display,dst=std{access=file,mux=mp4,dst=xyz.mp4}");
after the call to libvlc_media_new_location.
Here's a C# version that you can easily adapt to C/C++
var currentDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var destination = Path.Combine(currentDirectory, "record.ts");
// Load native libvlc library
Core.Initialize();
using (var libvlc = new LibVLC())
using (var mediaPlayer = new MediaPlayer(libvlc))
{
// Redirect log output to the console
libvlc.Log += (sender, e) => Console.WriteLine($"[{e.Level}] {e.Module}:{e.Message}");
// Create new media with HLS link
var media = new Media(libvlc, "http://hls1.addictradio.net/addictrock_aac_hls/playlist.m3u8", FromType.FromLocation);
// Define stream output options.
// In this case stream to a file with the given path and play locally the stream while streaming it.
media.AddOption(":sout=#file{dst=" + destination + "}");
media.AddOption(":sout-keep");
// Start recording
mediaPlayer.Play(media);
Console.WriteLine($"Recording in {destination}");
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
Related
I'm new to C++ and Windows and trying to write a WinRT/C++ app that can grab a file via path and run it through the built-in Media::Ocr model, but I can't see to even properly get the file into my application as a StorageFile. Here's how I've been trying to do it (to no avail):
runModel()
---------
IAsyncAction runModel() {
string _pth = "pic.png";
hstring pth = to_hstring(_pth);
StorageFile file = nullptr;
co_await LoadFileAsync(pth);
}
IAsyncAction LoadFileAsync (hstring pth) {
StorageFile file = co_await Windows::Storage::StorageFile::GetFileFromPathAsync(pth);
co_await LoadImageAsync(file);
}
IAsyncAction LoadImageAsync(StorageFile const& file) {
auto stream = co_await file.OpenAsync(Windows::Storage::FileAccessMode::Read);
auto decoder = co_await BitmapDecoder::CreateAsync(stream);
auto bitmap = co_await decoder.GetSoftwareBitmapAsync();
auto imgSource = WriteableBitmap(bitmap.PixelWidth(), bitmap.PixelHeight());
bitmap.CopyToBuffer(imgSource.PixelBuffer());
OcrEngine ocrEngine = nullptr;
ocrEngine = OcrEngine::TryCreateFromUserProfileLanguages();
auto ocrResult = co_await ocrEngine.RecognizeAsync(bitmap);
hstring hresult = ocrResult.Text();
std::cout << hresult.begin();
}
I'd appreciate any help of the following:
Loading the file in as a StorageFile
The right way to handle these async calls. I tried to follow https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/concurrency but I couldn't seem to get it to work without this error: !isStaThread()
How to properly do the OCR
Thanks!
I am new in AWS and Asp NetCore. Help me to find the solution.
I am using Asp NetCore, how should I use lambda function to upload clipped file in s3?
I have a IFormFile but I want to use s3 url instead of IFormFile and upload in s3 bucket. I have used ffmpeg library to cut the video and I want to send url of s3 using lambda function and upload the output of clipped video file again in s3 bucket directory that i created in s3 console.
using Abp.UI;
using FFmpeg.NET;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using System;
using System.IO;
using Amazon.S3;
using System.Threading.Tasks;
using Amazon.S3.Transfer;
using Amazon.S3.Model;
using IdentityModel.Client;
using Amazon;
using System.Net.Http;
namespace VideoSlicer.About
{
public class AboutAppService : IAboutAppService
{
//Assigning readonly IHostingEnvironment
private readonly IHostingEnvironment _appEnvironment;
private readonly string bucketName = "videoslicerpuru";
private static readonly RegionEndpoint bucketRegion = RegionEndpoint.Region;
/*
private const string newFile = "QQ.mp4";
private const string newFile1 = "637156754716419260QQ.mp4";
private const string filePath = #"C:\Users\Purushottam\Downloads\VideoSlicer\5.1.1\aspnet-core\src\VideoSlicer.Web.Host\wwwroot\images\";*/
private static IAmazonS3 client;
//Making Constructor and passin IHostingEnvironment
public AboutAppService(IHostingEnvironment appEnvironment)
{
_appEnvironment = appEnvironment;
}
//Function which upload video and slice video accordingly start time and finish time given by the user
public async Task UploadImage(IFormFile file, string Start, string Finish)
{
HttpClient cli = new HttpClient();
cli.DefaultRequestHeaders.ExpectContinue = false;
try
{
//Taking out the extension of the file
var convertedExtension = file.FileName.Substring(file.FileName.LastIndexOf("."));
//Comparing the extension whether uploaded file is video or not
if (convertedExtension != ".mp4" && convertedExtension != ".flv" && convertedExtension != ".3GP" && convertedExtension != ".OGG" && convertedExtension != ".AVI" && convertedExtension != ".WMV ")
{
throw new UserFriendlyException("Please Select Valid Video file to clip!!");
}
//Checking if the file is null or has not been selected any file
if (file == null || file.Length == 0)
{
throw new UserFriendlyException("Please Select any file.");
}
//declaring web root path
string path_Root = _appEnvironment.WebRootPath;
//setting path root and saving video to the given path
string pathOfVideo = path_Root + "\\video\\";
string path_to_Video = path_Root + "\\images\\" + file.FileName;
using (var stream = new FileStream(path_to_Video, FileMode.Create))
{
await file.CopyToAsync(stream);
}
client = new AmazonS3Client("AccessKey", "SecretKey", bucketRegion);
TransferUtility utility = new TransferUtility(client);
TransferUtilityUploadRequest request = new TransferUtilityUploadRequest();
string nameOfFile = file.FileName.ToString();
string videoPath = path_to_Video.ToString();
await utility.UploadAsync(videoPath, bucketName, nameOfFile);
Console.WriteLine("Upload 2 completed");
//To cut video, using ffmpeg media file where the video is saved
var input = new MediaFile(path_to_Video);
//The output of the clipped video and saving in a different folder
string nameFile = DateTime.Now.Ticks + file.FileName;
string nameBucket = bucketName + "/videoslice/";
var output = new MediaFile(path_Root + "/video/" + nameFile);
client = new AmazonS3Client(bucketRegion);
//making the object of Engine using ffmpeg application file
var ffmpeg = new Engine("C:\\ffmpeg\\bin\\ffmpeg.exe");
//making object of Conversion Option of ffmpeg
var options = new ConversionOptions();
//Converting string to double
var startTime = Convert.ToDouble($"{Start}");
var finishTime = Convert.ToDouble($"{Finish}");
//clipping video by given user input
options.CutMedia(TimeSpan.FromSeconds(startTime), TimeSpan.FromSeconds(finishTime - startTime));
await ffmpeg.ConvertAsync(input, output, options);
string clipPath = path_Root + "\\video\\" + nameFile;
//Checking if start time is greater then finish time
if (startTime > finishTime)
{
throw new UserFriendlyException("Please Enter Valid Second to proceed");
}
//Checking if start time is equal to finish time
if (startTime == finishTime)
{
throw new UserFriendlyException("Please Enter Valid Second to proceed");
}
var a = utility.UploadAsync(clipPath, nameBucket, nameFile);
Console.WriteLine("Upload 2 completed");
}
catch (AmazonS3Exception e)
{
string err = e.Message;
throw e;
}
catch (InternalBufferOverflowException a)
{
string me = a.Message;
throw a;
}
catch (HttpRequestException c)
{
string error = c.Message;
throw c;
}
catch (DriveNotFoundException e)
{
string mes = e.Message;
throw e;
}
catch(NullReferenceException e)
{
throw new UserFriendlyException (500, "Please Select a file to proceed",e.Message);
}
}
}
}
The aspose.barcode reader is unable to read the barcode of type DecodeType.Code128
Workflow Steps
1>Using Aspose.Barcode we have created a barcode using DecodeType.Code128 and put on PDF page ( our clients use this page as separator sheet)
2>Our client then insert this barcode page between several physical documents and scanned them all, which creates big single PDF
3>Our splitting process then, loop through all pages and check if any page is barcode page, and splits the big PDF into individual small PDF
Issue is some times the scanned quality of the barcode is not that great, and in such case ASPOSE.Barcode unable to read the barcode.
I have attached couple of barcode PDF with low scanned quality, and aspose is not able to read these barcodes. I have tried different combinations of RecognitionMode and ManualHints options without any luck
Below is my code to identity barcode page
using (var fs = new FileStream(file, FileMode.Open))
{
var pdfDocument = new Document(fs);
foreach (Page page in pdfDocument.Pages)
{
var isSeparator = splitter.IsSeparator(page);
Assert.IsTrue(isSeparator);
}
}
public bool IsSeparator(Page page)
{
if (page.Resources.Images != null && page.Resources.Images.Count >= 1)
{
var img = page.Resources.Images[1];
using (MemoryStream barcodeImage = new MemoryStream())
{
img.Save(barcodeImage, ImageFormat.Jpeg);
barcodeImage.Seek(0L, SeekOrigin.Begin);
using (BarCodeReader barcodeReader = new BarCodeReader(barcodeImage, _barcodeDecodeType))
{
barcodeReader.RecognitionMode = RecognitionMode.MaxQuality;
while (barcodeReader.Read())
{
var barcodeText = barcodeReader.GetCodeText();
if (barcodeText.ToLower() == "eof")
{
return true;
}
}
}
}
}
return false;
}
Unable to reproduce the issue at my end. I used the following sample code snippet to recognize the barcode along with latest version of the API. It is always recommended to use the latest version of the API as it contains new features and improvements.
CODE:
Aspose.Pdf.License licensePdf = new Aspose.Pdf.License();
licensePdf.SetLicense(#"Aspose.Total.lic");
// bind the pdf document
Aspose.Pdf.Facades.PdfExtractor pdfExtractor = new Aspose.Pdf.Facades.PdfExtractor();
pdfExtractor.BindPdf(#"173483_2.pdf");
// extract the images
pdfExtractor.ExtractImage();
// save images to stream in a loop
while (pdfExtractor.HasNextImage())
{
// save image to stream
System.IO.MemoryStream imageStream = new System.IO.MemoryStream();
pdfExtractor.GetNextImage(imageStream);
imageStream.Position = 0;
Aspose.BarCode.BarCodeRecognition.BarCodeReader barcodeReader =
new Aspose.BarCode.BarCodeRecognition.BarCodeReader(imageStream);
while (barcodeReader.Read())
{
Console.WriteLine("Codetext found: " + barcodeReader.GetCodeText() + ", Symbology: " + barcodeReader.GetCodeType().ToString());
}
// close the reader
barcodeReader.Close();
}
Further to update you that the same query has been post on Aspose.BarCode support forum. You may please visit the link for details.
I work as developer evangelist at Aspose.
I am trying to query a list of available video capture devices (webcams) on windows using gstreamer 1.0 in c++.
I am using ksvideosrc as source and i am able to capture the video input but i can't query a list of available devices (and their caps).
On gstreamer 0.10 it has been possible through GstPropertyProbe which is removed in gstreamer 1.0. The documentation suggests using GstDeviceMonitor. But i have no luck using that either.
Has anyone succeeded in acquiring a list of device names? Or can you suggests another way of retrieving the available device names and their caps?
You can use GstDeviceMonitor and gst_device_monitor_get_devices () function.
First initialize GstDeviceMonitor by gst_device_monitor_new().
Second start the monitor by gst_device_monitor_start(pMonitor).
Third, get devices list by gst_device_monitor_get_devices(pMonitor).
Code would be like this:
GstDeviceMonitor* monitor= gst_device_monitor_new();
if(!gst_device_monitor_start(monitor)){
printf("WARNING: Monitor couldn't started!!\n");
}
GList* devices = gst_device_monitor_get_devices(monitor);
My references:
https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstDeviceMonitor.html#gst-device-monitor-get-devices
Although I haven't figured out how to enumerate the device names, I've come up with a workaround to at least get the available ksvideosrc device indexes. Below is the code in Python, but you should be able to port it to C++ fairly easily, thanks to the GObject introspection bindings.
from gi.repository import Gst
def get_ksvideosrc_device_indexes():
device_index = 0
video_src = Gst.ElementFactory.make('ksvideosrc')
state_change_code = None
while True:
video_src.set_state(Gst.State.NULL)
video_src.set_property('device-index', device_index)
state_change_code = video_src.set_state(Gst.State.READY)
if state_change_code != Gst.StateChangeReturn.SUCCESS:
video_src.set_state(Gst.State.NULL)
break
device_index += 1
return range(device_index)
if __name__ == '__main__':
Gst.init()
print get_ksvideosrc_device_indexes()
Note that the video source device-name property is None as of GStreamer version 1.4.5.0 on Windows for the ksvideosrc.
It's very late, but for the future...
The Gst.DeviceMonitor can be used to enumerate devices, and register an addition or removal of a device.
Here's how to get device names in C# with GStreamer 1.14
static class Devices
{
public static void Run(string[] args)
{
Application.Init(ref args);
GtkSharp.GstreamerSharp.ObjectManager.Initialize();
var devmon = new DeviceMonitor();
// to show only cameras
// var caps = new Caps("video/x-raw");
// var filtId = devmon.AddFilter("Video/Source", caps);
var bus = devmon.Bus;
bus.AddWatch(OnBusMessage);
if (!devmon.Start())
{
"Device monitor cannot start".PrintErr();
return;
}
Console.WriteLine("Video devices count = " + devmon.Devices.Length);
foreach (var dev in devmon.Devices)
DumpDevice(dev);
var loop = new GLib.MainLoop();
loop.Run();
}
static void DumpDevice(Device d)
{
Console.WriteLine($"{d.DeviceClass} : {d.DisplayName} : {d.Name} ");
}
static bool OnBusMessage(Bus bus, Message message)
{
switch (message.Type)
{
case MessageType.DeviceAdded:
{
var dev = message.ParseDeviceAdded();
Console.WriteLine("Device added: ");
DumpDevice(dev);
break;
}
case MessageType.DeviceRemoved:
{
var dev = message.ParseDeviceRemoved();
Console.WriteLine("Device removed: ");
DumpDevice(dev);
break;
}
}
return true;
}
}
I am trying to implement a screenshot functionality in a WinRT app that shows Video via a MediaElement. I have the following code, it saves a screenshot that's the size of the MediaElement but the image is empty (completely black). Tried with various types of Media files. If I do a Win Key + Vol Down on Surface RT, the screen shot includes the Media frame content, but if I use the following code, it's blackness all around :(
private async Task SaveCurrentFrame()
{
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(Player);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
MultimediaItem currentItem = (MultimediaItem)this.DefaultViewModel["Group"];
StorageFolder currentFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
var saveFile = await currentFolder.CreateFileAsync(currentItem.UniqueId + ".png", CreationCollisionOption.ReplaceExisting);
if (saveFile == null)
return;
// Encode the image to the selected file on disk
using (var fileStream = await saveFile.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
}
Here MultimediaItem is my View Model class that among other things has a UniqueId property that's a string.
'Player' is the name of the Media Element.
Is there anything wrong with the code or this approach is wrong and I've to get in the trenches with C++?
P.S. I am interested in the WinRT API only.
Update 1 Looks like RenderTargetBitmap doesn't support this, the MSDN documentation clarifies it http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.imaging.rendertargetbitmap .
I'll appreciate any pointers on how to do it using DirectX C++. This is a major task for me so I'll crack this one way or the other and report back with the solution.
Yes, it is possible - little bit tricky, but working well.
You dont use mediaElement, but StorageFile itself.
You need to create writableBitmap with help of Windows.Media.Editing namespace.
Works in UWP (Windows 10)
This is complete example with file picking and getting video resolution and saving image to Picture Library
TimeSpan timeOfFrame = new TimeSpan(0, 0, 1);//one sec
//pick mp4 file
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
picker.FileTypeFilter.Add(".mp4");
StorageFile pickedFile = await picker.PickSingleFileAsync();
if (pickedFile == null)
{
return;
}
///
//Get video resolution
List<string> encodingPropertiesToRetrieve = new List<string>();
encodingPropertiesToRetrieve.Add("System.Video.FrameHeight");
encodingPropertiesToRetrieve.Add("System.Video.FrameWidth");
IDictionary<string, object> encodingProperties = await pickedFile.Properties.RetrievePropertiesAsync(encodingPropertiesToRetrieve);
uint frameHeight = (uint)encodingProperties["System.Video.FrameHeight"];
uint frameWidth = (uint)encodingProperties["System.Video.FrameWidth"];
///
//Use Windows.Media.Editing to get ImageStream
var clip = await MediaClip.CreateFromFileAsync(pickedFile);
var composition = new MediaComposition();
composition.Clips.Add(clip);
var imageStream = await composition.GetThumbnailAsync(timeOfFrame, (int)frameWidth, (int)frameHeight, VideoFramePrecision.NearestFrame);
///
//generate bitmap
var writableBitmap = new WriteableBitmap((int)frameWidth, (int)frameHeight);
writableBitmap.SetSource(imageStream);
//generate some random name for file in PicturesLibrary
var saveAsTarget = await KnownFolders.PicturesLibrary.CreateFileAsync("IMG" + Guid.NewGuid().ToString().Substring(0, 4) + ".jpg");
//get stream from bitmap
Stream stream = writableBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
using (var writeStream = await saveAsTarget.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, writeStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)writableBitmap.PixelWidth,
(uint)writableBitmap.PixelHeight,
96,
96,
pixels);
await encoder.FlushAsync();
using (var outputStream = writeStream.GetOutputStreamAt(0))
{
await outputStream.FlushAsync();
}
}
Yeah...I spent lot of hours by this
Ok I have managed to get making snapshot from MediaElement on button press to work.
I am passing MediaStreamSource object to MediaElement using SetMediaStreamSource method. MediaStreamSource has event SampleRequested which is fired basicly everytime new frame is drawn. Then using boolean I control when to create bitmap
private async void MediaStream_SampleRequested(MediaStreamSource sender, MediaStreamSourceSampleRequestedEventArgs args)
{
if (!takeSnapshot)
{
return;
}
takeSnapshot = false;
Task.Run(() => DecodeAndSaveVideoFrame(args.Request.Sample));
}
After that what is left is to decode compressed image and convert it to WriteableBitmap. The image is (or at least was in my case) in YUV fromat. You can get the byte array using
byte[] yvuArray = sample.Buffer.ToArray();
and then get data from this array and convert it to RGB. Unfortunetly I cannot post entire code but I'm gonna give you a few more hints:
YUV to RGB wiki here you have wiki describing how does YUV to RGB conversion works.
Here I found python project which solution I have adapted (and works perfectly). To be more precise you have to analize how method NV12Converter works.
The last thing is to change takeSnapshot boolean to true after pressing button or doing other activity :).