From 6270aac9594ac0e11c092d658ca34f719d5ff34b Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sat, 9 Nov 2019 22:01:20 +0100 Subject: [PATCH] Adding an option dictionary for the dash creation. --- Kyoo.Transcoder/{src => include}/helper.h | 2 +- .../{src/Stream.h => include/stream.h} | 8 +- .../Transcoder.h => include/transcoder.h} | 0 Kyoo.Transcoder/src/Transcoder.cpp | 108 +++++++++--------- Kyoo.Transcoder/src/helper.cpp | 28 ++--- .../src/app/player/player.component.html | 1 - .../src/app/player/player.component.ts | 2 +- Kyoo/InternalAPI/Transcoder/Transcoder.cs | 9 +- 8 files changed, 79 insertions(+), 79 deletions(-) rename Kyoo.Transcoder/{src => include}/helper.h (91%) rename Kyoo.Transcoder/{src/Stream.h => include/stream.h} (71%) rename Kyoo.Transcoder/{src/Transcoder.h => include/transcoder.h} (100%) diff --git a/Kyoo.Transcoder/src/helper.h b/Kyoo.Transcoder/include/helper.h similarity index 91% rename from Kyoo.Transcoder/src/helper.h rename to Kyoo.Transcoder/include/helper.h index f33ed34a..30025384 100644 --- a/Kyoo.Transcoder/src/helper.h +++ b/Kyoo.Transcoder/include/helper.h @@ -7,5 +7,5 @@ extern "C" } int open_input_context(AVFormatContext** inputContext, const char* path); AVStream* copy_stream_to_output(AVFormatContext* out_ctx, AVStream* in_stream); -int open_output_file_for_write(AVFormatContext* out_ctx, const char* out_path); +int open_output_file_for_write(AVFormatContext* out_ctx, const char* out_path, AVDictionary **options); void process_packet(AVPacket& pkt, AVStream* in_stream, AVStream* out_stream); \ No newline at end of file diff --git a/Kyoo.Transcoder/src/Stream.h b/Kyoo.Transcoder/include/stream.h similarity index 71% rename from Kyoo.Transcoder/src/Stream.h rename to Kyoo.Transcoder/include/stream.h index 079dd173..2717f49d 100644 --- a/Kyoo.Transcoder/src/Stream.h +++ b/Kyoo.Transcoder/include/stream.h @@ -13,15 +13,15 @@ extern "C" struct Stream char *title; char *language; char *codec; - bool isDefault; - bool isForced; + bool is_default; + bool is_forced; char *path; Stream() - : title(NULL), language(NULL), codec(NULL), isDefault(NULL), isForced(NULL), path(NULL) {} + : title(NULL), language(NULL), codec(NULL), is_default(NULL), is_forced(NULL), path(NULL) {} Stream(const char* title, const char* languageCode, const char* codec, bool isDefault, bool isForced) - : title(NULL), language(NULL), codec(NULL), isDefault(isDefault), isForced(isForced), path(NULL) + : title(NULL), language(NULL), codec(NULL), is_default(isDefault), is_forced(isForced), path(NULL) { if(title != NULL) this->title= strdup(title); diff --git a/Kyoo.Transcoder/src/Transcoder.h b/Kyoo.Transcoder/include/transcoder.h similarity index 100% rename from Kyoo.Transcoder/src/Transcoder.h rename to Kyoo.Transcoder/include/transcoder.h diff --git a/Kyoo.Transcoder/src/Transcoder.cpp b/Kyoo.Transcoder/src/Transcoder.cpp index fb38aebd..4c0b47c1 100644 --- a/Kyoo.Transcoder/src/Transcoder.cpp +++ b/Kyoo.Transcoder/src/Transcoder.cpp @@ -8,13 +8,14 @@ int Init() return sizeof(Stream); } -int transmux(const char *path, const char *out_path) +int transmux(const char *path, const char *out_path, const char *get_uri) { AVFormatContext *in_ctx = NULL; - AVFormatContext* out_ctx = NULL; - AVStream* stream; + AVFormatContext *out_ctx = NULL; + AVStream *stream; AVPacket pkt; - int* stream_map; + AVDictionary *options = NULL; + int *stream_map; int stream_count; int ret = 0; @@ -52,7 +53,10 @@ int transmux(const char *path, const char *out_path) } av_dump_format(out_ctx, 0, out_path, true); - if (open_output_file_for_write(out_ctx, out_path) != 0) + + av_dict_set(&options, "init_seg_name", ((std::string)get_uri + (std::string)"/init-stream$RepresentationID$.m4s").c_str(), AV_DICT_DONT_STRDUP_VAL); + av_dict_set(&options, "media_seg_name", ((std::string)get_uri + (std::string)"/chunk-stream$RepresentationID$-$Number%05d$.m4s").c_str(), AV_DICT_DONT_STRDUP_VAL); + if (open_output_file_for_write(out_ctx, out_path, &options) != 0) return 1; while (av_read_frame(in_ctx, &pkt) == 0) @@ -91,8 +95,8 @@ int transmux(const char *path, const char *out_path) Stream *extract_subtitles(const char *path, const char *out_path, int *stream_count, int *subtitle_count) { AVFormatContext *int_ctx = NULL; - AVFormatContext** output_list; - Stream* streams; + AVFormatContext **output_list; + Stream *streams; AVPacket pkt; unsigned int out_count; @@ -104,51 +108,51 @@ Stream *extract_subtitles(const char *path, const char *out_path, int *stream_co streams = new Stream[*stream_count]; out_count = int_ctx->nb_streams; - output_list = new AVFormatContext*[out_count]; + output_list = new AVFormatContext *[out_count]; //Initialize output and set headers. for (unsigned int i = 0; i < int_ctx->nb_streams; i++) { - AVStream *inputStream = int_ctx->streams[i]; - const AVCodecParameters *inputCodecpar = inputStream->codecpar; + AVStream *in_stream = int_ctx->streams[i]; + const AVCodecParameters *in_codecpar = in_stream->codecpar; - if (inputCodecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) + if (in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) output_list[i] = NULL; else { *subtitle_count += 1; - AVDictionaryEntry *languagePtr = av_dict_get(inputStream->metadata, "language", NULL, 0); + AVDictionaryEntry *languageptr = av_dict_get(in_stream->metadata, "language", NULL, 0); //Get metadata for file name streams[i] = Stream(NULL, //title - languagePtr ? languagePtr->value : NULL, //language - avcodec_get_name(inputCodecpar->codec_id), //format - inputStream->disposition & AV_DISPOSITION_DEFAULT, //isDefault - inputStream->disposition & AV_DISPOSITION_FORCED); //isForced + languageptr ? languageptr->value : NULL, //language + avcodec_get_name(in_codecpar->codec_id), //format + in_stream->disposition & AV_DISPOSITION_DEFAULT, //isDefault + in_stream->disposition & AV_DISPOSITION_FORCED); //isForced //Create the language subfolder - std::stringstream outStream; - outStream << out_path << (char)std::filesystem::path::preferred_separator << streams[i].language; - std::filesystem::create_directory(outStream.str()); + std::stringstream out_strstream; + out_strstream << out_path << (char)std::filesystem::path::preferred_separator << streams[i].language; + std::filesystem::create_directory(out_strstream.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); + std::string file_name(path); + size_t last_separator = file_name.find_last_of((char)std::filesystem::path::preferred_separator); + file_name = file_name.substr(last_separator, file_name.find_last_of('.') - last_separator); //Construct output file name - outStream << fileName << "." << streams[i].language; + out_strstream << file_name << "." << streams[i].language; - if (streams[i].isDefault) - outStream << ".default"; - if (streams[i].isForced) - outStream << ".forced"; + if (streams[i].is_default) + out_strstream << ".default"; + if (streams[i].is_forced) + out_strstream << ".forced"; if (strcmp(streams[i].codec, "subrip") == 0) - outStream << ".srt"; + out_strstream << ".srt"; else if (strcmp(streams[i].codec, "ass") == 0) - outStream << ".ass"; + out_strstream << ".ass"; else { std::cout << "Unsupported subtitle codec: " << streams[i].codec << std::endl; @@ -156,36 +160,36 @@ Stream *extract_subtitles(const char *path, const char *out_path, int *stream_co continue; } - streams[i].path = strdup(outStream.str().c_str()); + streams[i].path = strdup(out_strstream.str().c_str()); - std::cout << "Stream #" << i << "(" << streams[i].language << "), stream type: " << inputCodecpar->codec_type << " codec: " << streams[i].codec << std::endl; + std::cout << "Stream #" << i << "(" << streams[i].language << "), stream type: " << in_codecpar->codec_type << " codec: " << streams[i].codec << std::endl; - AVFormatContext *outputContext = NULL; - if (avformat_alloc_output_context2(&outputContext, NULL, NULL, streams[i].path) < 0) + AVFormatContext *out_ctx = NULL; + if (avformat_alloc_output_context2(&out_ctx, NULL, NULL, streams[i].path) < 0) { std::cout << "Error: Couldn't create an output file." << std::endl; continue; } - av_dict_copy(&outputContext->metadata, int_ctx->metadata, NULL); + av_dict_copy(&out_ctx->metadata, int_ctx->metadata, NULL); - AVStream *outputStream = copy_stream_to_output(outputContext, inputStream); - if (outputStream == NULL) + AVStream *out_stream = copy_stream_to_output(out_ctx, in_stream); + if (out_stream == NULL) goto end; - av_dump_format(outputContext, 0, streams[i].path, true); + av_dump_format(out_ctx, 0, streams[i].path, true); - if (open_output_file_for_write(outputContext, streams[i].path) != 0) + if (open_output_file_for_write(out_ctx, streams[i].path, NULL) != 0) goto end; - output_list[i] = outputContext; + output_list[i] = out_ctx; if (false) { end: - if (outputContext && !(outputContext->flags & AVFMT_NOFILE)) - avio_closep(&outputContext->pb); - avformat_free_context(outputContext); + if (out_ctx && !(out_ctx->flags & AVFMT_NOFILE)) + avio_closep(&out_ctx->pb); + avformat_free_context(out_ctx); output_list[i] = nullptr; std::cout << "An error occured, cleaning up th output context for the stream #" << i << std::endl; @@ -199,17 +203,17 @@ Stream *extract_subtitles(const char *path, const char *out_path, int *stream_co if ((unsigned int)pkt.stream_index >= out_count) continue; - AVFormatContext *outputContext = output_list[pkt.stream_index]; - if (outputContext == nullptr) + AVFormatContext *out_ctx = output_list[pkt.stream_index]; + if (out_ctx == nullptr) { av_packet_unref(&pkt); continue; } - process_packet(pkt, int_ctx->streams[pkt.stream_index], outputContext->streams[0]); + process_packet(pkt, int_ctx->streams[pkt.stream_index], out_ctx->streams[0]); pkt.stream_index = 0; - if (av_interleaved_write_frame(outputContext, &pkt) < 0) + if (av_interleaved_write_frame(out_ctx, &pkt) < 0) std::cout << "Error while writing a packet to the output file." << std::endl; av_packet_unref(&pkt); @@ -219,16 +223,16 @@ Stream *extract_subtitles(const char *path, const char *out_path, int *stream_co for (unsigned int i = 0; i < out_count; i++) { - AVFormatContext *outputContext = output_list[i]; + AVFormatContext *out_ctx = output_list[i]; - if (outputContext == NULL) + if (out_ctx == NULL) continue; - av_write_trailer(outputContext); + av_write_trailer(out_ctx); - if (outputContext && !(outputContext->flags & AVFMT_NOFILE)) - avio_closep(&outputContext->pb); - avformat_free_context(outputContext); + if (out_ctx && !(out_ctx->flags & AVFMT_NOFILE)) + avio_closep(&out_ctx->pb); + avformat_free_context(out_ctx); } delete[] output_list; diff --git a/Kyoo.Transcoder/src/helper.cpp b/Kyoo.Transcoder/src/helper.cpp index 5e438902..5ca9f3b2 100644 --- a/Kyoo.Transcoder/src/helper.cpp +++ b/Kyoo.Transcoder/src/helper.cpp @@ -1,25 +1,25 @@ #include "helper.h" #include -int open_input_context(AVFormatContext** inputContext, const char* path) +int open_input_context(AVFormatContext **in_ctx, const char *path) { - if (avformat_open_input(inputContext, path, NULL, NULL)) + if (avformat_open_input(in_ctx, path, NULL, NULL)) { std::cout << "Error: Can't open the file at " << path << std::endl; return 1; } - if (avformat_find_stream_info(*inputContext, NULL) < 0) + if (avformat_find_stream_info(*in_ctx, NULL) < 0) { std::cout << "Error: Could't find streams informations for the file at " << path << std::endl; return 1; } - av_dump_format(*inputContext, 0, path, false); + av_dump_format(*in_ctx, 0, path, false); return 0; } -AVStream* copy_stream_to_output(AVFormatContext* out_ctx, AVStream* in_stream) +AVStream *copy_stream_to_output(AVFormatContext *out_ctx, AVStream *in_stream) { - AVStream* out_stream = avformat_new_stream(out_ctx, NULL); + AVStream *out_stream = avformat_new_stream(out_ctx, NULL); if (out_stream == NULL) { @@ -33,7 +33,7 @@ AVStream* copy_stream_to_output(AVFormatContext* out_ctx, AVStream* in_stream) } out_stream->codecpar->codec_tag = 0; avformat_transfer_internal_stream_timing_info(out_ctx->oformat, out_stream, in_stream, AVTimebaseSource::AVFMT_TBCF_AUTO); - out_stream->time_base = av_add_q(av_stream_get_codec_timebase(out_stream), AVRational{ 0, 1 }); + out_stream->time_base = av_add_q(av_stream_get_codec_timebase(out_stream), AVRational {0, 1}); out_stream->duration = av_rescale_q(in_stream->duration, in_stream->time_base, out_stream->time_base); out_stream->disposition = in_stream->disposition; out_stream->avg_frame_rate = in_stream->avg_frame_rate; @@ -46,27 +46,27 @@ constexpr enum AVRounding operator |(const enum AVRounding a, const enum AVRound return (enum AVRounding)(uint32_t(a) | uint32_t(b)); } -int open_output_file_for_write(AVFormatContext* outputContext, const char* outputPath) +int open_output_file_for_write(AVFormatContext *out_ctx, const char *out_path, AVDictionary **options) { - if (!(outputContext->flags & AVFMT_NOFILE)) + if (!(out_ctx->flags & AVFMT_NOFILE)) { - if (avio_open(&outputContext->pb, outputPath, AVIO_FLAG_WRITE) < 0) + if (avio_open(&out_ctx->pb, out_path, AVIO_FLAG_WRITE) < 0) { - std::cout << "Error: Couldn't open file at " << outputPath << std::endl; + std::cout << "Error: Couldn't open file at " << out_path << std::endl; return 1; } } else std::cout << "Output flag set to AVFMT_NOFILE." << std::endl; - if (avformat_write_header(outputContext, NULL) < 0) + if (avformat_write_header(out_ctx, options) < 0) { - std::cout << "Error: Couldn't write headers to file at " << outputPath << std::endl; + std::cout << "Error: Couldn't write headers to file at " << out_path << std::endl; return 1; } return 0; } -void process_packet(AVPacket& pkt, AVStream* in_stream, AVStream* out_stream) +void process_packet(AVPacket &pkt, AVStream *in_stream, AVStream *out_stream) { pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); diff --git a/Kyoo/ClientApp/src/app/player/player.component.html b/Kyoo/ClientApp/src/app/player/player.component.html index 39c9135d..9a5998d8 100644 --- a/Kyoo/ClientApp/src/app/player/player.component.html +++ b/Kyoo/ClientApp/src/app/player/player.component.html @@ -1,7 +1,6 @@
diff --git a/Kyoo/ClientApp/src/app/player/player.component.ts b/Kyoo/ClientApp/src/app/player/player.component.ts index 11b4398d..9da645b7 100644 --- a/Kyoo/ClientApp/src/app/player/player.component.ts +++ b/Kyoo/ClientApp/src/app/player/player.component.ts @@ -339,7 +339,7 @@ export class PlayerComponent implements OnInit init() { var dashPlayer = MediaPlayer().create(); - dashPlayer.initialize(this.player, "/video/transmux/" + this.item.link, true); + dashPlayer.initialize(this.player, "http://localhost:5005/" + this.item.link + "/" + this.item.link + ".mpd", true); let sub: string = this.route.snapshot.queryParams["sub"]; if (sub != null) diff --git a/Kyoo/InternalAPI/Transcoder/Transcoder.cs b/Kyoo/InternalAPI/Transcoder/Transcoder.cs index 8c1bc8f3..eb750572 100644 --- a/Kyoo/InternalAPI/Transcoder/Transcoder.cs +++ b/Kyoo/InternalAPI/Transcoder/Transcoder.cs @@ -31,14 +31,11 @@ namespace Kyoo.InternalAPI }); } - public void GetVideo(string path) - { - Debug.WriteLine("&Getting video..."); - } - public string Transmux(WatchItem episode) { - string temp = Path.Combine(tempPath, episode.Link + "/" + episode.Link + ".mpd"); + string temp = Path.Combine(tempPath, episode.Link); + Directory.CreateDirectory(temp); + temp = Path.Combine(temp, episode.Link + ".mpd"); Debug.WriteLine("&Transmuxing " + episode.Link + " at " + episode.Path + ", outputPath: " + temp); if (File.Exists(temp) || TranscoderAPI.transmux(episode.Path, temp) == 0) return temp;