diff --git a/Kyoo.Transcoder/Kyoo.Transcoder.vcxproj b/Kyoo.Transcoder/Kyoo.Transcoder.vcxproj
index a4162a91..4d9f4280 100644
--- a/Kyoo.Transcoder/Kyoo.Transcoder.vcxproj
+++ b/Kyoo.Transcoder/Kyoo.Transcoder.vcxproj
@@ -101,6 +101,7 @@
WIN32;_DEBUG;KYOOTRANSCODER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);TRANSCODER_EXPORTS=1
true
pch.h
+ stdcpp17
Windows
@@ -120,6 +121,7 @@
true
pch.h
%(AdditionalIncludeDirectories)
+ stdcpp17
Windows
@@ -140,6 +142,7 @@
WIN32;NDEBUG;KYOOTRANSCODER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);TRANSCODER_EXPORTS=1
true
pch.h
+ stdcpp17
Windows
@@ -163,6 +166,7 @@
true
pch.h
%(AdditionalIncludeDirectories)
+ stdcpp17
Windows
diff --git a/Kyoo.Transcoder/src/Transcoder.cpp b/Kyoo.Transcoder/src/Transcoder.cpp
index fcebf480..4c61b981 100644
--- a/Kyoo.Transcoder/src/Transcoder.cpp
+++ b/Kyoo.Transcoder/src/Transcoder.cpp
@@ -1,4 +1,6 @@
#include "pch.h"
+#include
+#include
#include "Transcoder.h"
//ffmpeg imports
@@ -6,8 +8,15 @@ extern "C"
{
#include
#include
+ #include
}
+constexpr enum AVRounding operator |(const enum AVRounding a, const enum AVRounding b)
+{
+ return (enum AVRounding)(uint32_t(a) | uint32_t(b));
+}
+
+
int Init()
{
@@ -30,16 +39,41 @@ void ExtractSubtitles(const char* path, const char* outPath)
return;
}
+ av_dump_format(inputContext, 0, path, false);
+
+ const unsigned int outputCount = inputContext->nb_streams;
+ AVFormatContext** outputList = new AVFormatContext*[outputCount]();
+
+ //Initialize output and set headers.
for (unsigned int i = 0; i < inputContext->nb_streams; i++)
{
AVStream* inputStream = inputContext->streams[i];
const AVCodecParameters* inputCodecpar = inputStream->codecpar;
- if (inputCodecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ if (inputCodecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
+ outputList[i] = nullptr;
+ else
{
- const char* output = outPath;
- const AVCodec* codec = avcodec_find_decoder(inputCodecpar->codec_id);
- std::cout << "Stream #" << i << ", stream type: " << inputCodecpar->codec_type << " codec: " << codec->name << " long name: " << codec->long_name << std::endl;
+ //Get metadata for file name
+ const char* language = av_dict_get(inputStream->metadata, "language", NULL, 0)->value;
+
+ std::cout << "Stream #" << i << "(" << language << "), stream type: " << inputCodecpar->codec_type << " codec: " << inputCodecpar->codec_tag << std::endl;
+
+ //Create output folder
+ std::stringstream outStream;
+ outStream << outPath << (char)std::filesystem::path::preferred_separator << language;
+ std::filesystem::create_directory(outStream.str());
+
+ //Get file name
+ std::string fileName(path);
+ size_t lastSeparator = fileName.find_last_of((char)std::filesystem::path::preferred_separator);
+ fileName = fileName.substr(lastSeparator, fileName.find_last_of('.') - lastSeparator);
+
+ //Construct output file name
+ outStream << fileName << "." << language;
+ outStream << ".ass";
+ std::string outStr = outStream.str();
+ const char* output = outStr.c_str();
AVFormatContext* outputContext = NULL;
if (avformat_alloc_output_context2(&outputContext, NULL, NULL, output) < 0)
@@ -48,16 +82,47 @@ void ExtractSubtitles(const char* path, const char* outPath)
continue;
}
- AVStream* outputStream = avformat_new_stream(outputContext, codec);
+ //outputContext->metadata = inputContext->metadata; //ITS A FUCKING POINTER
+
+ AVStream* outputStream = avformat_new_stream(outputContext, NULL);
if (outputStream == NULL)
{
std::cout << "Error: Couldn't create stream." << std::endl;
- avformat_free_context(outputContext);
- return;
+ goto end;
}
- AVCodecParameters* outputCodecpar = outputStream->codecpar;
- avcodec_parameters_copy(outputCodecpar, inputCodecpar);
+ if (avcodec_parameters_copy(outputStream->codecpar, inputCodecpar) < 0)
+ {
+ std::cout << "Error: Couldn't copy parameters to the output file." << std::endl;
+ goto end;
+ }
+ outputStream->codecpar->codec_tag = 0;
+
+ outputStream->duration = av_rescale_q(inputStream->duration, inputStream->time_base, outputStream->time_base);
+
+ av_dump_format(outputContext, 0, output, true);
+
+ if (!(outputContext->flags & AVFMT_NOFILE))
+ {
+ if (avio_open(&outputContext->pb, output, AVIO_FLAG_WRITE) < 0)
+ {
+ std::cout << "Error: Couldn't open file at " << output << std::endl;
+ goto end;
+ }
+ }
+ else
+ std::cout << "Output flag set to AVFMT_NOFILE." << std::endl;
+
+ if (avformat_write_header(outputContext, NULL) < 0)
+ {
+ std::cout << "Error: Couldn't write headers to file at " << output << std::endl;
+ goto end;
+ }
+
+ #pragma region global metadata try
+ //avformat_transfer_internal_stream_timing_info(outputContext->oformat, outputStream, inputStream, AVTimebaseSource::AVFMT_TBCF_AUTO);
+
+ //outputStream->time_base = av_add_q(av_stream_get_codec_timebase(outputStream), AVRational{ 0, 1 });
//outputStream->disposition = inputStream->disposition;
@@ -78,55 +143,67 @@ void ExtractSubtitles(const char* path, const char* outPath)
// memcpy(newPkt, sidePkt->data, sidePkt->size);
// }
//}
+#pragma endregion
- if (avio_open(&outputContext->pb, output, AVIO_FLAG_WRITE) < 0)
+ outputList[i] = outputContext;
+
+ if (false)
{
- std::cout << "Error: Couldn't open file at " << output << std::endl;
+ end:
+ if (outputContext && !(outputContext->flags & AVFMT_NOFILE))
+ avio_closep(&outputContext->pb);
avformat_free_context(outputContext);
- return;
+
+ outputList[i] = nullptr;
+ std::cout << "An error occured, cleaning up th output context for the stream #" << i << std::endl;
}
-
- if (avformat_write_header(outputContext, NULL) < 0)
- {
- std::cout << "Error: Couldn't write headers to file at " << output << std::endl;
- avformat_free_context(outputContext);
- avio_closep(&outputContext->pb);
- return;
- }
-
- AVPacket pkt;
- int i = 0;
- while (av_read_frame(inputContext, &pkt) == 0)
- {
- if (pkt.stream_index != inputStream->index)
- continue;
-
- std::cout << "Reading packet... " << i << std::endl;
- i++;
-
- pkt.pts = av_rescale_q_rnd(pkt.pts, inputStream->time_base, outputStream->time_base, AV_ROUND_NEAR_INF);
- pkt.dts = av_rescale_q_rnd(pkt.dts, inputStream->time_base, outputStream->time_base, AV_ROUND_NEAR_INF);
- pkt.duration = av_rescale_q(pkt.duration, inputStream->time_base, outputStream->time_base);
- pkt.pos = -1;
- pkt.stream_index = 0;
-
- if (av_interleaved_write_frame(outputContext, &pkt) < 0)
- {
- //Should handle packet copy error;
- }
-
- av_packet_unref(&pkt);
- }
- av_write_trailer(outputContext);
-
- avio_closep(&outputContext->pb);
- avformat_free_context(outputContext);
-
- goto end;
}
}
-end:
+ //Write subtitle data to files.
+ AVPacket pkt;
+ while (av_read_frame(inputContext, &pkt) == 0)
+ {
+ //if (pkt.stream_index >= outputCount)
+ // continue;
+
+ AVFormatContext* outputContext = outputList[pkt.stream_index];
+ if(outputContext == nullptr)
+ {
+ av_packet_unref(&pkt);
+ continue;
+ }
+
+ AVStream* inputStream = inputContext->streams[pkt.stream_index];
+ AVStream* outputStream = outputContext->streams[0];
+
+ pkt.stream_index = 0;
+
+ pkt.pts = av_rescale_q_rnd(pkt.pts, inputStream->time_base, outputStream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
+ pkt.dts = av_rescale_q_rnd(pkt.dts, inputStream->time_base, outputStream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
+ pkt.duration = av_rescale_q(pkt.duration, inputStream->time_base, outputStream->time_base);
+ pkt.pos = -1;
+
+ if (av_interleaved_write_frame(outputContext, &pkt) < 0)
+ {
+ std::cout << "Error while writing a packet to the output file." << std::endl;
+ }
+
+ av_packet_unref(&pkt);
+ }
+
avformat_close_input(&inputContext);
- return;
+
+ for (unsigned int i = 0; i < outputCount; i++)
+ {
+ AVFormatContext* outputContext = outputList[i];
+
+ av_write_trailer(outputContext);
+
+ if (outputContext && !(outputContext->flags & AVFMT_NOFILE))
+ avio_closep(&outputContext->pb);
+ avformat_free_context(outputContext);
+ }
+
+ delete[] outputList;
}
\ No newline at end of file
diff --git a/Kyoo/InternalAPI/Transcoder/Transcoder.cs b/Kyoo/InternalAPI/Transcoder/Transcoder.cs
index 8f0048ee..fda8d94f 100644
--- a/Kyoo/InternalAPI/Transcoder/Transcoder.cs
+++ b/Kyoo/InternalAPI/Transcoder/Transcoder.cs
@@ -14,8 +14,8 @@ namespace Kyoo.InternalAPI
public void ExtractSubtitles(string path)
{
- string output = Path.GetDirectoryName(path);
- output = Path.Combine(output, "fre\\output.ass");
+ string output = Path.Combine(Path.GetDirectoryName(path), "Subtitles");
+ Directory.CreateDirectory(output);
TranscoderAPI.ExtractSubtitles(path, output);
}