mirror of
https://github.com/zoriya/Kyoo.git
synced 2026-06-06 06:15:16 -04:00
Adding an option dictionary for the dash creation.
This commit is contained in:
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
#ifdef TRANSCODER_EXPORTS
|
||||
#define API __declspec(dllexport)
|
||||
#else
|
||||
#define API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
extern "C" struct Stream
|
||||
{
|
||||
char *title;
|
||||
char *language;
|
||||
char *codec;
|
||||
bool isDefault;
|
||||
bool isForced;
|
||||
char *path;
|
||||
|
||||
Stream()
|
||||
: title(NULL), language(NULL), codec(NULL), isDefault(NULL), isForced(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)
|
||||
{
|
||||
if(title != NULL)
|
||||
this->title= strdup(title);
|
||||
|
||||
if (languageCode != NULL)
|
||||
language = strdup(languageCode);
|
||||
else
|
||||
language = strdup("und");
|
||||
|
||||
if (codec != NULL)
|
||||
this->codec = strdup(codec);
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
#ifdef TRANSCODER_EXPORTS
|
||||
#define API __declspec(dllexport)
|
||||
#else
|
||||
#define API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include "Stream.h"
|
||||
|
||||
|
||||
extern "C" API int Init();
|
||||
|
||||
extern "C" API int transmux(const char *path, const char *outPath);
|
||||
|
||||
//Take the path of the file and the path of the output directory. It will return the list of subtitle streams in the streams variable. The int returned is the number of subtitles extracted.
|
||||
extern "C" API Stream* extract_subtitles(const char *path, const char *outPath, int *streamCount, int *subtitleCount);
|
||||
|
||||
extern "C" API void free_memory(Stream *streamsPtr);
|
||||
@@ -1,25 +1,25 @@
|
||||
#include "helper.h"
|
||||
#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;
|
||||
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);
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
extern "C"
|
||||
{
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/dict.h>
|
||||
#include <libavutil/timestamp.h>
|
||||
}
|
||||
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);
|
||||
void process_packet(AVPacket& pkt, AVStream* in_stream, AVStream* out_stream);
|
||||
Reference in New Issue
Block a user