Splitting a video in four files in C# - c#

I am doing a research of how to split a video in four fragments. I have seen a lot of solutions and libraries. I was looking at this library:
https://github.com/AydinAdn/MediaToolkit
And this is the code for splitting the video
var inputFile = new MediaFile {Filename = #"C:\Path\To_Video.flv"};
var outputFile = new MediaFile {Filename = #"C:\Path\To_Save_ExtractedVideo.flv"};
using (var engine = new Engine())
{
engine.GetMetadata(inputFile);
var options = new ConversionOptions();
// This example will create a 25 second video, starting from the
// 30th second of the original video.
//// First parameter requests the starting frame to cut the media from.
//// Second parameter requests how long to cut the video.
options.CutMedia(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(25));
engine.Convert(inputFile, outputFile, options);
}
The code is splitting just one fragment. Is there a way to split it in four fragments?
Kind regards
PS: the solution must be in C# and already have seen the Directshow solution.

It works well for me, but I'll fix the algorithm, because I'm missing the final video following, the code I have at the moment is this:
static void Main(string[] args)
{
using (var engine = new Engine())
{
string file = #"C:\Users\wilso\Downloads\IZA - Meu Talismã.mp4";
var inputFile = new MediaFile { Filename = file };
engine.GetMetadata(inputFile);
var outputName = #"C:\Users\wilso\Downloads\output";
var outputExtension = ".mp4";
double Duration = inputFile.Metadata.Duration.TotalSeconds;
double currentPosition = 0;
int contador = 0;
while (currentPosition < Duration)
{
currentPosition = contador * 30;
contador++;
var options = new ConversionOptions();
var outputFile = new MediaFile(outputName + contador.ToString("00") + outputExtension);
options.CutMedia(TimeSpan.FromSeconds(currentPosition), TimeSpan.FromSeconds(30));
engine.Convert(inputFile, outputFile, options);
}
}
}

I haven't used this library before but this is how I would go about it.
var inputFile = new MediaFile {Filename = #"C:\Path\To_Video.flv"};
var outputName = "C:\Path\To_Save_ExtractedVideo";
var outputExtension = ".flv";
double t = inputFile.Length/4; //length of parts -- need to use method to get file playtime length
for(int i=0;i<4;i++){
var engine = new Engine()
engine.GetMetadata(inputFile);
var options = new ConversionOptions();
// This example will create a 25 second video, starting from the
// 30th second of the original video.
//// First parameter requests the starting frame to cut the media from.
//// Second parameter requests how long to cut the video.
options.CutMedia(TimeSpan.FromSeconds(30 + (i*int.Parse(t))), TimeSpan.FromSeconds((i+1)*int.Parse(t)));
engine.Convert(inputFile, $"{outputName}_{i.ToString()}{outputExtension}, options);
engine.Destroy(); // Need to destroy object or close inputstream. Whichever the library offers
}
}

Related

How to extract all pages and attachments from PDF to PNG

I am trying to create a process in .NET to convert a PDF and all it's pages + attachments to PNGs. I am evaluating libraries and came across PDFiumSharp but it is not working for me. Here is my code:
string Inputfile = "input.pdf";
string OutputFolder = "Output";
string fileName = Path.GetFileNameWithoutExtension(Inputfile);
using (PdfDocument doc = new PdfDocument(Inputfile))
{
for (int i = 0; i < doc.Pages.Count; i++)
{
var page = doc.Pages[i];
using (var bitmap = new PDFiumBitmap((int)page.Width, (int)page.Height, false))
{
page.Render(bitmap);
var targetFile = Path.Combine(OutputFolder, fileName + "_" + i + ".png");
bitmap.Save(targetFile);
}
}
}
When I run this code, I get this exception:
screenshot of exception
Does anyone know how to fix this? Also does PDFiumSharp support extracting PDF attachments? If not, does anyone have any other ideas on how to achieve my goal?
PDFium does not look like it supports extracting PDF attachments. If you want to achieve your goal, then you can take a look at another library that supports both extracting PDF attachments as well as converting PDFs to PNGs.
I am an employee of the LEADTOOLS PDF SDK which you can try out via these 2 nuget packages:
https://www.nuget.org/packages/Leadtools.Pdf/
https://www.nuget.org/packages/Leadtools.Document.Sdk/
Here is some code that will convert a PDF + all attachments in the PDF to separate PNGs in an output directory:
SetLicense();
cache = new FileCache { CacheDirectory = "cache" };
List<LEADDocument> documents = new List<LEADDocument>();
if (!Directory.Exists(OutputDir))
Directory.CreateDirectory(OutputDir);
using var document = DocumentFactory.LoadFromFile("attachments.pdf", new LoadDocumentOptions { Cache = cache, LoadAttachmentsMode = DocumentLoadAttachmentsMode.AsAttachments });
if (document.Pages.Count > 0)
documents.Add(document);
foreach (var attachment in document.Attachments)
documents.Add(document.LoadDocumentAttachment(new LoadAttachmentOptions { AttachmentNumber = attachment.AttachmentNumber }));
ConvertDocuments(documents, RasterImageFormat.Png);
And the ConvertDocuments method:
static void ConvertDocuments(IEnumerable<LEADDocument> documents, RasterImageFormat imageFormat)
{
using var converter = new DocumentConverter();
using var ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);
ocrEngine.Startup(null, null, null, null);
converter.SetOcrEngineInstance(ocrEngine, false);
converter.SetDocumentWriterInstance(new DocumentWriter());
foreach (var document in documents)
{
var name = string.IsNullOrEmpty(document.Name) ? "Attachment" : document.Name;
string outputFile = Path.Combine(OutputDir, $"{name}.{RasterCodecs.GetExtension(imageFormat)}");
int count = 1;
while (File.Exists(outputFile))
outputFile = Path.Combine(OutputDir, $"{name}({count++}).{RasterCodecs.GetExtension(imageFormat)}");
var jobData = new DocumentConverterJobData
{
Document = document,
Cache = cache,
DocumentFormat = DocumentFormat.User,
RasterImageFormat = imageFormat,
RasterImageBitsPerPixel = 0,
OutputDocumentFileName = outputFile,
};
var job = converter.Jobs.CreateJob(jobData);
converter.Jobs.RunJob(job);
}
}

AcmNotPossible calling acmStreamOpen Error

In my application i have some Audio files those are in .wav Format, Here i am checking Each audio file BitRate , and if any file in below 128Kbps,i changed those files bit rate to 128kbps,by using Below code
int bitrate;
string FullPath = #Server.MapPath("~/AudioFiles/");
string[] filePaths = Directory.GetFiles(FullPath, "*.wav", SearchOption.AllDirectories);
for (int i = 0; i < filePaths.Length; i++)
{
string[] FileExt = filePaths[i].Split('\\');
string[] Ext = FileExt[FileExt.Length - 1].Split('.');
string ExtFile = Ext[Ext.Length - 1];
if (ExtFile == "wav" || ExtFile == "WAV")
{
using (var reader = new WaveFileReader(filePaths[i]))
{
bitrate = reader.WaveFormat.AverageBytesPerSecond * 8;
reader.Dispose();
}
if (bitrate < 128000)
{
using (var reader = new WaveFileReader(filePaths[i]))
{
var newFormat = new WaveFormat(8000, 16, 1);
using (var conversionStream = new WaveFormatConversionStream(newFormat, reader))
{
WaveFileWriter.CreateWaveFile(Server.MapPath("~/AudioFiles/" + FileExt[FileExt.Length - 1]), conversionStream);
}
}
}
}
the above code is working for most of the files, But i get below error for some audio files.
how can i solve the issue?
You can typically only change one thing at a time with ACM, so if you have a 16kHz stereo file, you can't go to an 8kHz mono file in one go.
So you need to see what WaveFormat your WaveFileReader has, and possibly do multiple conversion steps.
It may also be that your input WAV file is using a codec that ACM can't decode. But again you'd need to examine your input WaveFormat to know that.

C# Download the sound of a youtube video

I can download a video from youtube but I want the sound only. How can I do that?
Code I have for downloading the video (Using VideoLibrary):
YouTube youtube = YouTube.Default;
Video vid = youtube.GetVideo(txt_youtubeurl.Text);
System.IO.File.WriteAllBytes(source + vid.FullName, vid.GetBytes());
Install the NuGet packages: MediaToolkit and VideoLibrary, it will allow you to do the conversion by file extension.
var source = #"<your destination folder>";
var youtube = YouTube.Default;
var vid = youtube.GetVideo("<video url>");
File.WriteAllBytes(source + vid.FullName, vid.GetBytes());
var inputFile = new MediaFile { Filename = source + vid.FullName };
var outputFile = new MediaFile { Filename = $"{source + vid.FullName}.mp3" };
using (var engine = new Engine())
{
engine.GetMetadata(inputFile);
engine.Convert(inputFile, outputFile);
}
The above code works awesome you don't need to download the video first I created this procedure so when rookies like myself see this makes it easier to use.
You need the nuget packages MediaToolkit and VideoLibrary.
example url: https://www.youtube.com/watch?v=lzm5llVmR2E
example path just needs a path to save file to.
just add the name of the mp3 file to save
Hope this helps someone I have tested this code;
private void SaveMP3(string SaveToFolder, string VideoURL, string MP3Name)
{
var source = #SaveToFolder;
var youtube = YouTube.Default;
var vid = youtube.GetVideo(VideoURL);
File.WriteAllBytes(source + vid.FullName, vid.GetBytes());
var inputFile = new MediaFile { Filename = source + vid.FullName };
var outputFile = new MediaFile { Filename = $"{MP3Name}.mp3" };
using (var engine = new Engine())
{
engine.GetMetadata(inputFile);
engine.Convert(inputFile, outputFile);
}
}
based on this topic, i have developed a simple and dumb program to Download a youtube playlist. Hope this helps someone. It's just a Main.cs file: Youtube Playlist Downloader - Mp4 & Mp3
Ok found a better way the above code didn't normalize the audio posting it for others.
First Add Nuget package: https://www.nuget.org/packages/NReco.VideoConverter/
To Convert MP4 to MP3
// Client
var client = new YoutubeClient();
var videoId = NormalizeVideoId(txtFileURL.Text);
var video = await client.GetVideoAsync(videoId);
var streamInfoSet = await client.GetVideoMediaStreamInfosAsync(videoId);
// Get the best muxed stream
var streamInfo = streamInfoSet.Muxed.WithHighestVideoQuality();
// Compose file name, based on metadata
var fileExtension = streamInfo.Container.GetFileExtension();
var fileName = $"{video.Title}.{fileExtension}";
// Replace illegal characters in file name
fileName = RemoveIllegalFileNameChars(fileName);
tmrVideo.Enabled = true;
// Download video
txtMessages.Text = "Downloading Video please wait ... ";
//using (var progress = new ProgressBar())
await client.DownloadMediaStreamAsync(streamInfo, fileName);
// Add Nuget package: https://www.nuget.org/packages/NReco.VideoConverter/ To Convert MP4 to MP3
if (ckbAudioOnly.Checked)
{
var Convert = new NReco.VideoConverter.FFMpegConverter();
String SaveMP3File = MP3FolderPath + fileName.Replace(".mp4", ".mp3");
Convert.ConvertMedia(fileName, SaveMP3File, "mp3");
//Delete the MP4 file after conversion
File.Delete(fileName);
LoadMP3Files();
txtMessages.Text = "File Converted to MP3";
tmrVideo.Enabled = false;
txtMessages.BackColor = Color.White;
if (ckbAutoPlay.Checked) { PlayFile(SaveMP3File); }
return;
}
I like the idea of using a method. I tried SaveMP3() but it had some problems.
This worked for me: `
private void SaveMP3(string SaveToFolder, string VideoURL, string MP3Name)
{
string source = SaveToFolder;
var youtube = YouTube.Default;
var vid = youtube.GetVideo(VideoURL);
string videopath = Path.Combine(source, vid.FullName);
File.WriteAllBytes(videopath, vid.GetBytes());
var inputFile = new MediaFile { Filename = Path.Combine(source, vid.FullName) };
var outputFile = new MediaFile { Filename = Path.Combine(source , $"{MP3Name}.mp3") };
using (var engine = new Engine())
{
engine.GetMetadata(inputFile);
engine.Convert(inputFile, outputFile);
}
File.Delete(Path.Combine(source, vid.FullName));
}
`

Telerik RenderReport

I have some problems with Telerik reports.
Feels like i have missed something...
I wanna create a list of reports, and then write them to ONE file.
But when i write it out i only get one page.
The writer writer over page 1 all foreach, so it just write one page.
But i want several pages... in this case 10.
Have tried write with FileStream, File and more...
Does anyone have a good idea?
public void WriteToFile()
{
string path = #"C:\";
string test = "test";
var report = new Report2();
var procceser = new ReportProcessor();
var list = new List<RenderingResult>();
for (int i = 0; i < 10; i++)
{
var res = procceser.RenderReport("PDF", report, null);
list.Add(res);
}
string filePath = Path.Combine(path, test);
var Writer = new BinaryWriter(File.Create(filePath));
foreach (var renderingResult in list)
{
Writer.Write(renderingResult.DocumentBytes);
}
Writer.Flush();
Writer.Close();
}

Update Google Doc from local file using google API possible ? (.NET / C# / WPF)

I am currently testing the google API. It seems promising, but I am stuck at a "simple" problem. I want to update an existing document with a local copy.
My idea was, download all google documents to a folder, using the doc-download. That works. At the next run, I check the dates, if a remote document is newer, grab it again. If the local document is newer, upload it, and replace the current online version.
I can't find a function to replace a document. There is a Upload(filename, doctitle) but this creates a new document. Does anybody know if this is possible and can point me in the correction direction. Do I have to dissect the atom feed (is the document content somewhere inside it..). The "download / change in word / upload" looked so nice :-)
Chris
And for anyone who is interested, its pretty simple and nice to use the API. Here is a short WPF example (without credentials, of course)
var settings = new RequestSettings("GoogleDocumentsSample", _credentials);
AllDocuments = new ObservableCollection<Document>();
settings.AutoPaging = true;
settings.PageSize = 10;
service = new DocumentsService("DocListUploader");
((GDataRequestFactory)service.RequestFactory).KeepAlive = false;
service.setUserCredentials(username, password);
//force the service to authenticate
var query = new DocumentsListQuery {NumberToRetrieve = 1};
service.Query(query);
var request = new DocumentsRequest(settings);
Feed<Document> feed = request.GetEverything();
// this takes care of paging the results in
foreach (Document entry in feed.Entries)
{
AllDocuments.Add(entry);
if (entry.Type == Document.DocumentType.Document)
{
var fI = new FileInfo(#"somepath" + entry.DocumentId + ".doc");
if (!fI.Exists || fI.LastWriteTime < entry.Updated)
{
Debug.WriteLine("Download doc " + entry.DocumentId);
var type = Document.DownloadType.doc;
Stream stream = request.Download(entry, type);
if (fI.Exists) fI.Delete();
Stream file = fI.OpenWrite();
int nBytes = 2048;
int count = 0;
Byte[] arr = new Byte[nBytes];
do
{
count = stream.Read(arr, 0, nBytes);
file.Write(arr, 0, count);
} while (count > 0);
file.Flush();
file.Close();
stream.Close();
fI.CreationTimeUtc = entry.Updated;
fI.LastWriteTimeUtc = entry.Updated;
}
else
{
if (entry.Updated == fI.LastWriteTime)
{
Debug.WriteLine("Document up to date " + entry.DocumentId);
}
else
{
Debug.WriteLine(String.Format("Local version newer {0} [LOCAL {1}] [REMOTE {2}]", entry.DocumentId, fI.LastWriteTimeUtc, entry.Updated));
service.UploadDocument(fI.FullName, entry.Title);
}
}
}
}
According to Docs API docs ;) you can replace the content of a document
http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#UpdatingContent

Categories