mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Adding an option dictionary for the dash creation.
This commit is contained in:
parent
05d297201e
commit
6270aac959
@ -7,5 +7,5 @@ extern "C"
|
|||||||
}
|
}
|
||||||
int open_input_context(AVFormatContext** inputContext, const char* path);
|
int open_input_context(AVFormatContext** inputContext, const char* path);
|
||||||
AVStream* copy_stream_to_output(AVFormatContext* out_ctx, AVStream* in_stream);
|
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);
|
void process_packet(AVPacket& pkt, AVStream* in_stream, AVStream* out_stream);
|
@ -13,15 +13,15 @@ extern "C" struct Stream
|
|||||||
char *title;
|
char *title;
|
||||||
char *language;
|
char *language;
|
||||||
char *codec;
|
char *codec;
|
||||||
bool isDefault;
|
bool is_default;
|
||||||
bool isForced;
|
bool is_forced;
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
Stream()
|
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)
|
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)
|
if(title != NULL)
|
||||||
this->title= strdup(title);
|
this->title= strdup(title);
|
@ -8,13 +8,14 @@ int Init()
|
|||||||
return sizeof(Stream);
|
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 *in_ctx = NULL;
|
||||||
AVFormatContext* out_ctx = NULL;
|
AVFormatContext *out_ctx = NULL;
|
||||||
AVStream* stream;
|
AVStream *stream;
|
||||||
AVPacket pkt;
|
AVPacket pkt;
|
||||||
int* stream_map;
|
AVDictionary *options = NULL;
|
||||||
|
int *stream_map;
|
||||||
int stream_count;
|
int stream_count;
|
||||||
int ret = 0;
|
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);
|
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;
|
return 1;
|
||||||
|
|
||||||
while (av_read_frame(in_ctx, &pkt) == 0)
|
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)
|
Stream *extract_subtitles(const char *path, const char *out_path, int *stream_count, int *subtitle_count)
|
||||||
{
|
{
|
||||||
AVFormatContext *int_ctx = NULL;
|
AVFormatContext *int_ctx = NULL;
|
||||||
AVFormatContext** output_list;
|
AVFormatContext **output_list;
|
||||||
Stream* streams;
|
Stream *streams;
|
||||||
AVPacket pkt;
|
AVPacket pkt;
|
||||||
unsigned int out_count;
|
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];
|
streams = new Stream[*stream_count];
|
||||||
|
|
||||||
out_count = int_ctx->nb_streams;
|
out_count = int_ctx->nb_streams;
|
||||||
output_list = new AVFormatContext*[out_count];
|
output_list = new AVFormatContext *[out_count];
|
||||||
|
|
||||||
//Initialize output and set headers.
|
//Initialize output and set headers.
|
||||||
for (unsigned int i = 0; i < int_ctx->nb_streams; i++)
|
for (unsigned int i = 0; i < int_ctx->nb_streams; i++)
|
||||||
{
|
{
|
||||||
AVStream *inputStream = int_ctx->streams[i];
|
AVStream *in_stream = int_ctx->streams[i];
|
||||||
const AVCodecParameters *inputCodecpar = inputStream->codecpar;
|
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;
|
output_list[i] = NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*subtitle_count += 1;
|
*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
|
//Get metadata for file name
|
||||||
streams[i] = Stream(NULL, //title
|
streams[i] = Stream(NULL, //title
|
||||||
languagePtr ? languagePtr->value : NULL, //language
|
languageptr ? languageptr->value : NULL, //language
|
||||||
avcodec_get_name(inputCodecpar->codec_id), //format
|
avcodec_get_name(in_codecpar->codec_id), //format
|
||||||
inputStream->disposition & AV_DISPOSITION_DEFAULT, //isDefault
|
in_stream->disposition & AV_DISPOSITION_DEFAULT, //isDefault
|
||||||
inputStream->disposition & AV_DISPOSITION_FORCED); //isForced
|
in_stream->disposition & AV_DISPOSITION_FORCED); //isForced
|
||||||
|
|
||||||
//Create the language subfolder
|
//Create the language subfolder
|
||||||
std::stringstream outStream;
|
std::stringstream out_strstream;
|
||||||
outStream << out_path << (char)std::filesystem::path::preferred_separator << streams[i].language;
|
out_strstream << out_path << (char)std::filesystem::path::preferred_separator << streams[i].language;
|
||||||
std::filesystem::create_directory(outStream.str());
|
std::filesystem::create_directory(out_strstream.str());
|
||||||
|
|
||||||
//Get file name
|
//Get file name
|
||||||
std::string fileName(path);
|
std::string file_name(path);
|
||||||
size_t lastSeparator = fileName.find_last_of((char)std::filesystem::path::preferred_separator);
|
size_t last_separator = file_name.find_last_of((char)std::filesystem::path::preferred_separator);
|
||||||
fileName = fileName.substr(lastSeparator, fileName.find_last_of('.') - lastSeparator);
|
file_name = file_name.substr(last_separator, file_name.find_last_of('.') - last_separator);
|
||||||
|
|
||||||
//Construct output file name
|
//Construct output file name
|
||||||
outStream << fileName << "." << streams[i].language;
|
out_strstream << file_name << "." << streams[i].language;
|
||||||
|
|
||||||
if (streams[i].isDefault)
|
if (streams[i].is_default)
|
||||||
outStream << ".default";
|
out_strstream << ".default";
|
||||||
if (streams[i].isForced)
|
if (streams[i].is_forced)
|
||||||
outStream << ".forced";
|
out_strstream << ".forced";
|
||||||
|
|
||||||
if (strcmp(streams[i].codec, "subrip") == 0)
|
if (strcmp(streams[i].codec, "subrip") == 0)
|
||||||
outStream << ".srt";
|
out_strstream << ".srt";
|
||||||
else if (strcmp(streams[i].codec, "ass") == 0)
|
else if (strcmp(streams[i].codec, "ass") == 0)
|
||||||
outStream << ".ass";
|
out_strstream << ".ass";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << "Unsupported subtitle codec: " << streams[i].codec << std::endl;
|
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;
|
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;
|
AVFormatContext *out_ctx = NULL;
|
||||||
if (avformat_alloc_output_context2(&outputContext, NULL, NULL, streams[i].path) < 0)
|
if (avformat_alloc_output_context2(&out_ctx, NULL, NULL, streams[i].path) < 0)
|
||||||
{
|
{
|
||||||
std::cout << "Error: Couldn't create an output file." << std::endl;
|
std::cout << "Error: Couldn't create an output file." << std::endl;
|
||||||
continue;
|
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);
|
AVStream *out_stream = copy_stream_to_output(out_ctx, in_stream);
|
||||||
if (outputStream == NULL)
|
if (out_stream == NULL)
|
||||||
goto end;
|
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;
|
goto end;
|
||||||
|
|
||||||
output_list[i] = outputContext;
|
output_list[i] = out_ctx;
|
||||||
|
|
||||||
if (false)
|
if (false)
|
||||||
{
|
{
|
||||||
end:
|
end:
|
||||||
if (outputContext && !(outputContext->flags & AVFMT_NOFILE))
|
if (out_ctx && !(out_ctx->flags & AVFMT_NOFILE))
|
||||||
avio_closep(&outputContext->pb);
|
avio_closep(&out_ctx->pb);
|
||||||
avformat_free_context(outputContext);
|
avformat_free_context(out_ctx);
|
||||||
|
|
||||||
output_list[i] = nullptr;
|
output_list[i] = nullptr;
|
||||||
std::cout << "An error occured, cleaning up th output context for the stream #" << i << std::endl;
|
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)
|
if ((unsigned int)pkt.stream_index >= out_count)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
AVFormatContext *outputContext = output_list[pkt.stream_index];
|
AVFormatContext *out_ctx = output_list[pkt.stream_index];
|
||||||
if (outputContext == nullptr)
|
if (out_ctx == nullptr)
|
||||||
{
|
{
|
||||||
av_packet_unref(&pkt);
|
av_packet_unref(&pkt);
|
||||||
continue;
|
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;
|
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;
|
std::cout << "Error while writing a packet to the output file." << std::endl;
|
||||||
|
|
||||||
av_packet_unref(&pkt);
|
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++)
|
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;
|
continue;
|
||||||
|
|
||||||
av_write_trailer(outputContext);
|
av_write_trailer(out_ctx);
|
||||||
|
|
||||||
if (outputContext && !(outputContext->flags & AVFMT_NOFILE))
|
if (out_ctx && !(out_ctx->flags & AVFMT_NOFILE))
|
||||||
avio_closep(&outputContext->pb);
|
avio_closep(&out_ctx->pb);
|
||||||
avformat_free_context(outputContext);
|
avformat_free_context(out_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] output_list;
|
delete[] output_list;
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
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;
|
std::cout << "Error: Can't open the file at " << path << std::endl;
|
||||||
return 1;
|
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;
|
std::cout << "Error: Could't find streams informations for the file at " << path << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
av_dump_format(*inputContext, 0, path, false);
|
av_dump_format(*in_ctx, 0, path, false);
|
||||||
return 0;
|
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)
|
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;
|
out_stream->codecpar->codec_tag = 0;
|
||||||
avformat_transfer_internal_stream_timing_info(out_ctx->oformat, out_stream, in_stream, AVTimebaseSource::AVFMT_TBCF_AUTO);
|
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->duration = av_rescale_q(in_stream->duration, in_stream->time_base, out_stream->time_base);
|
||||||
out_stream->disposition = in_stream->disposition;
|
out_stream->disposition = in_stream->disposition;
|
||||||
out_stream->avg_frame_rate = in_stream->avg_frame_rate;
|
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));
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << "Output flag set to AVFMT_NOFILE." << std::endl;
|
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 1;
|
||||||
}
|
}
|
||||||
return 0;
|
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.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);
|
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<div id="root">
|
<div id="root">
|
||||||
<div class="player data-vjs-player">
|
<div class="player data-vjs-player">
|
||||||
<video id="player" poster="backdrop/{{this.item.showSlug}}" autoplay muted (click)="videoClicked()">
|
<video id="player" poster="backdrop/{{this.item.showSlug}}" autoplay muted (click)="videoClicked()">
|
||||||
<source src="https://dash.akamaized.net/envivio/EnvivioDash3/manifest.mpd" />
|
|
||||||
</video>
|
</video>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -339,7 +339,7 @@ export class PlayerComponent implements OnInit
|
|||||||
init()
|
init()
|
||||||
{
|
{
|
||||||
var dashPlayer = MediaPlayer().create();
|
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"];
|
let sub: string = this.route.snapshot.queryParams["sub"];
|
||||||
if (sub != null)
|
if (sub != null)
|
||||||
|
@ -31,14 +31,11 @@ namespace Kyoo.InternalAPI
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetVideo(string path)
|
|
||||||
{
|
|
||||||
Debug.WriteLine("&Getting video...");
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Transmux(WatchItem episode)
|
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);
|
Debug.WriteLine("&Transmuxing " + episode.Link + " at " + episode.Path + ", outputPath: " + temp);
|
||||||
if (File.Exists(temp) || TranscoderAPI.transmux(episode.Path, temp) == 0)
|
if (File.Exists(temp) || TranscoderAPI.transmux(episode.Path, temp) == 0)
|
||||||
return temp;
|
return temp;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user