Cleaning up

This commit is contained in:
Zoe Roux
2020-04-12 02:55:42 +02:00
parent 2c5df13c7d
commit cb506de30d
9 changed files with 211 additions and 212 deletions

View File

@@ -1 +0,0 @@
./configure --pkg-config-flags=--static --disable-shared --enable-static --disable-zlib --disable-iconv --disable-asm --disable-ffplay --disable-ffprobe

View File

@@ -4,10 +4,10 @@
typedef enum
{
none = 0,
video = 1,
audio = 2,
subtitle = 3
none = 0,
video = 1,
audio = 2,
subtitle = 3
} type;
typedef struct stream

View File

@@ -7,19 +7,19 @@
void destroy_stream(stream *s)
{
if (s->title)
free(s->title);
if (s->language)
free(s->language);
if (s->codec)
free(s->codec);
if (s->path)
free(s->path);
if (s->title)
free(s->title);
if (s->language)
free(s->language);
if (s->codec)
free(s->codec);
if (s->path)
free(s->path);
}
void free_streams(stream *s, int count)
{
for (unsigned i = 0; i < count; i++)
destroy_stream(s + i);
free(s);
for (unsigned i = 0; i < count; i++)
destroy_stream(s + i);
free(s);
}

View File

@@ -65,15 +65,15 @@ void process_packet(AVPacket *pkt, AVStream *in_stream, AVStream *out_stream)
type type_fromffmpeg(int type)
{
switch (type)
{
case AVMEDIA_TYPE_VIDEO:
return video;
case AVMEDIA_TYPE_AUDIO:
return audio;
case AVMEDIA_TYPE_SUBTITLE:
return subtitle;
default:
return none;
}
switch (type)
{
case AVMEDIA_TYPE_VIDEO:
return video;
case AVMEDIA_TYPE_AUDIO:
return audio;
case AVMEDIA_TYPE_SUBTITLE:
return subtitle;
default:
return none;
}
}

View File

@@ -8,8 +8,8 @@
int init()
{
puts("Kyoo's transcoder initiated.");
return (sizeof(stream));
puts("Kyoo's transcoder initiated.");
return (sizeof(stream));
}
stream *get_track_info(const char *path, unsigned *stream_count, unsigned *track_count)

View File

@@ -11,67 +11,67 @@
char *strrnchr(const char *str, int c, int occ_to_skip)
{
const char *ptr = str + strlen(str);
const char *ptr = str + strlen(str);
while (ptr != str) {
if (*str == c) {
occ_to_skip--;
if (occ_to_skip == 0)
return ((char *)str);
}
str--;
}
return (NULL);
while (ptr != str) {
if (*str == c) {
occ_to_skip--;
if (occ_to_skip == 0)
return ((char *)str);
}
str--;
}
return (NULL);
}
char *path_getfolder(const char *path)
{
char *start;
char *end;
char *folder;
char *start;
char *end;
char *folder;
start = strrnchr(path, '/', 1);
end = strrchr(path, '/');
if (!end)
return (NULL);
folder = strndup(start, end - start);
return (folder);
start = strrnchr(path, '/', 1);
end = strrchr(path, '/');
if (!end)
return (NULL);
folder = strndup(start, end - start);
return (folder);
}
char *path_getfilename(const char *path)
{
const char *name = strrchr(path, '/') ? strrchr(path, '/') + 1 : path;
int len = strrchr(path, '.') ? strrchr(path, '.') - name : 1024;
const char *name = strrchr(path, '/') ? strrchr(path, '/') + 1 : path;
int len = strrchr(path, '.') ? strrchr(path, '.') - name : 1024;
return (strndup(name, len));
return (strndup(name, len));
}
char *get_extension_from_codec(char *codec)
{
if (!codec)
return (NULL);
if (!strcmp(codec, "subrip"))
return(".srt");
else if (!strcmp(codec, "ass"))
return(".ass");
else {
printf("Unsupported subtitle codec: %s.\n", codec);
free(codec);
return (NULL);
}
if (!codec)
return (NULL);
if (!strcmp(codec, "subrip"))
return(".srt");
else if (!strcmp(codec, "ass"))
return(".ass");
else {
printf("Unsupported subtitle codec: %s.\n", codec);
free(codec);
return (NULL);
}
}
int path_mkdir(const char *path, int mode)
{
int ret;
struct stat s;
int ret;
struct stat s;
if (!path)
return (-1);
ret = kmkdir(path, mode);
if (ret < 0 && errno == EEXIST && stat(path, &s) == 0) {
if (S_ISDIR(s.st_mode))
return (0);
}
return (ret);
if (!path)
return (-1);
ret = kmkdir(path, mode);
if (ret < 0 && errno == EEXIST && stat(path, &s) == 0) {
if (S_ISDIR(s.st_mode))
return (0);
}
return (ret);
}

View File

@@ -17,10 +17,10 @@ int get_subtitle_data(stream *substream, AVStream *in_stream, const char *file_n
AVDictionaryEntry *languageptr = av_dict_get(in_stream->metadata, "language", NULL, 0);
char *codec = strdup(avcodec_get_name(in_stream->codecpar->codec_id));
char *extension = get_extension_from_codec(codec);
char *folder_path;
char *folder_path;
if (!extension)
return (-1);
if (!extension)
return (-1);
*substream = (stream) {
NULL,
languageptr ? strdup(languageptr->value) : NULL,
@@ -31,18 +31,18 @@ int get_subtitle_data(stream *substream, AVStream *in_stream, const char *file_n
subtitle
};
asprintf(&folder_path, "%s/%s", out_path, substream->language);
if (path_mkdir(folder_path, 0733) < 0) {
if (!folder_path)
free(folder_path);
return (-1);
}
if (path_mkdir(folder_path, 0733) < 0) {
if (!folder_path)
free(folder_path);
return (-1);
}
asprintf(&substream->path, "%s/%s.%s%s%s%s", folder_path,
file_name,
substream->language,
substream->is_default ? ".default" : "",
substream->is_forced ? ".forced" : "",
extension);
free(folder_path);
free(folder_path);
if (!substream->path)
return (-1);
return (0);
@@ -110,53 +110,53 @@ void finish_up(AVFormatContext *int_ctx, AVFormatContext **output_list, unsigned
int split_inputfile(AVFormatContext *int_ctx, AVFormatContext **output_list, stream *streams, char *path, const char *out_path)
{
int subcount = 0;
char *file_name = path_getfilename(path);
int subcount = 0;
char *file_name = path_getfilename(path);
if (!file_name)
return (-1);
for (unsigned int i = 0; i < int_ctx->nb_streams; i++) {
AVStream *in_stream = int_ctx->streams[i];
if (!file_name)
return (-1);
for (unsigned int i = 0; i < int_ctx->nb_streams; i++) {
AVStream *in_stream = int_ctx->streams[i];
if (in_stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
if (get_subtitle_data(streams + i, in_stream, file_name, out_path) == 0 &&
copy_subtitle_stream(&output_list[i], streams + i, int_ctx, in_stream) == 0) {
subcount += 1;
continue;
}
fprintf(stderr,"Couldn't copy the %s subtitle to output\n", streams[i].language);
destroy_stream(&streams[i]);
}
streams[i] = NULLSTREAM;
output_list[i] = NULL;
}
free(file_name);
return (subcount);
if (in_stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
if (get_subtitle_data(streams + i, in_stream, file_name, out_path) == 0 &&
copy_subtitle_stream(&output_list[i], streams + i, int_ctx, in_stream) == 0) {
subcount += 1;
continue;
}
fprintf(stderr,"Couldn't copy the %s subtitle to output\n", streams[i].language);
destroy_stream(&streams[i]);
}
streams[i] = NULLSTREAM;
output_list[i] = NULL;
}
free(file_name);
return (subcount);
}
stream *extract_subtitles(char *path, const char *out_path, unsigned *stream_count, unsigned *subtitle_count)
{
AVFormatContext *int_ctx = NULL;
AVFormatContext **output_list;
stream *streams;
stream *streams;
if (open_input_context(&int_ctx, path) != 0)
return (NULL);
return (NULL);
*stream_count = int_ctx->nb_streams;
streams = calloc(sizeof(stream), *stream_count);
output_list = malloc(sizeof(AVFormatContext *) * *stream_count);
if (streams && output_list) {
*subtitle_count = split_inputfile(int_ctx, output_list, streams, path, out_path);
if (*subtitle_count >= 0) {
write_data(int_ctx, output_list, *stream_count);
finish_up(int_ctx, output_list, *stream_count);
return (streams);
}
}
*subtitle_count = split_inputfile(int_ctx, output_list, streams, path, out_path);
if (*subtitle_count >= 0) {
write_data(int_ctx, output_list, *stream_count);
finish_up(int_ctx, output_list, *stream_count);
return (streams);
}
}
*subtitle_count = 0;
if (streams)
free_streams(streams, (int)*stream_count);
if (output_list)
free(output_list);
return (NULL);
if (streams)
free_streams(streams, (int)*stream_count);
if (output_list)
free(output_list);
return (NULL);
}

View File

@@ -10,118 +10,118 @@
static bool should_copy_to_transmuxed(enum AVMediaType codec_type)
{
if (codec_type == AVMEDIA_TYPE_VIDEO)
return (true);
if (codec_type == AVMEDIA_TYPE_AUDIO)
return (true);
return (false);
if (codec_type == AVMEDIA_TYPE_VIDEO)
return (true);
if (codec_type == AVMEDIA_TYPE_AUDIO)
return (true);
return (false);
}
static int *prepare_streammap(AVFormatContext *in_ctx, AVFormatContext *out_ctx)
{
int *stream_map = malloc(sizeof(int) * in_ctx->nb_streams);
int stream_count = 0;
AVStream *stream;
int *stream_map = malloc(sizeof(int) * in_ctx->nb_streams);
int stream_count = 0;
AVStream *stream;
if (!stream_map)
return (NULL);
for (unsigned i = 0; i < in_ctx->nb_streams; i++) {
stream = in_ctx->streams[i];
if (should_copy_to_transmuxed(stream->codecpar->codec_type)) {
stream_map[i] = stream_count;
stream_count++;
if (!copy_stream_to_output(out_ctx, stream)) {
free(stream_map);
return (NULL);
}
} else
stream_map[i] = -1;
}
return (stream_map);
if (!stream_map)
return (NULL);
for (unsigned i = 0; i < in_ctx->nb_streams; i++) {
stream = in_ctx->streams[i];
if (should_copy_to_transmuxed(stream->codecpar->codec_type)) {
stream_map[i] = stream_count;
stream_count++;
if (!copy_stream_to_output(out_ctx, stream)) {
free(stream_map);
return (NULL);
}
} else
stream_map[i] = -1;
}
return (stream_map);
}
static AVDictionary *create_options_context(const char *out_path)
{
AVDictionary *options = NULL;
char seg_path[strlen(out_path) + 22];
int folder_index = strrchr(out_path, '/') - out_path;
AVDictionary *options = NULL;
char seg_path[strlen(out_path) + 22];
int folder_index = strrchr(out_path, '/') - out_path;
sprintf(seg_path, "%.*s/segments/", folder_index, out_path);
if (path_mkdir(seg_path, 0733) < 0) {
fprintf(stderr, "Error: Couldn't create segment output folder. Part of the output path does not exist or you don't have write rights.\n");
return (NULL);
}
strcat(seg_path, "%v-%03d.ts");
av_dict_set(&options, "hls_segment_filename", seg_path, 0);
av_dict_set(&options, "hls_base_url", "segment/", 0);
av_dict_set(&options, "hls_list_size", "0", 0);
av_dict_set(&options, "streaming", "1", 0);
return (options);
sprintf(seg_path, "%.*s/segments/", folder_index, out_path);
if (path_mkdir(seg_path, 0733) < 0) {
fprintf(stderr, "Error: Couldn't create segment output folder. Part of the output path does not exist or you don't have write rights.\n");
return (NULL);
}
strcat(seg_path, "%v-%03d.ts");
av_dict_set(&options, "hls_segment_filename", seg_path, 0);
av_dict_set(&options, "hls_base_url", "segment/", 0);
av_dict_set(&options, "hls_list_size", "0", 0);
av_dict_set(&options, "streaming", "1", 0);
return (options);
}
static void write_to_output(AVFormatContext *in_ctx, AVFormatContext *out_ctx, int *stream_map, float *playable_duration)
{
AVPacket pkt;
AVStream *istream;
AVStream *ostream;
int index;
AVPacket pkt;
AVStream *istream;
AVStream *ostream;
int index;
while (av_read_frame(in_ctx, &pkt) == 0) {
index = pkt.stream_index;
if (index >= in_ctx->nb_streams || stream_map[index] < 0) {
av_packet_unref(&pkt);
continue;
}
istream = in_ctx->streams[index];
ostream = out_ctx->streams[stream_map[index]];
pkt.stream_index = stream_map[index];
process_packet(&pkt, istream, ostream);
if (pkt.stream_index == 0)
*playable_duration += pkt.duration * (float)ostream->time_base.num / ostream->time_base.den;
if (av_interleaved_write_frame(out_ctx, &pkt) < 0)
fprintf(stderr, "Error while writing a packet to the output file.\n");
av_packet_unref(&pkt);
}
while (av_read_frame(in_ctx, &pkt) == 0) {
index = pkt.stream_index;
if (index >= in_ctx->nb_streams || stream_map[index] < 0) {
av_packet_unref(&pkt);
continue;
}
istream = in_ctx->streams[index];
ostream = out_ctx->streams[stream_map[index]];
pkt.stream_index = stream_map[index];
process_packet(&pkt, istream, ostream);
if (pkt.stream_index == 0)
*playable_duration += pkt.duration * (float)ostream->time_base.num / ostream->time_base.den;
if (av_interleaved_write_frame(out_ctx, &pkt) < 0)
fprintf(stderr, "Error while writing a packet to the output file.\n");
av_packet_unref(&pkt);
}
}
static void destroy_context(AVFormatContext *in_ctx, AVFormatContext *out_ctx, AVDictionary *options, int *stream_map)
{
if (options)
av_dict_free(&options);
av_write_trailer(out_ctx);
avformat_close_input(&in_ctx);
if (out_ctx && !(out_ctx->oformat->flags & AVFMT_NOFILE))
avio_close(out_ctx->pb);
avformat_free_context(out_ctx);
if (stream_map)
free(stream_map);
if (options)
av_dict_free(&options);
av_write_trailer(out_ctx);
avformat_close_input(&in_ctx);
if (out_ctx && !(out_ctx->oformat->flags & AVFMT_NOFILE))
avio_close(out_ctx->pb);
avformat_free_context(out_ctx);
if (stream_map)
free(stream_map);
}
int transmux(const char *path, const char *out_path, float *playable_duration)
{
AVFormatContext *in_ctx = NULL;
AVFormatContext *out_ctx = NULL;
AVDictionary *options = NULL;
int *stream_map;
AVDictionary *options = NULL;
int *stream_map;
*playable_duration = 0;
*playable_duration = 0;
av_log_set_level(AV_LOG_WARNING);
if (open_input_context(&in_ctx, path) != 0) {
fprintf(stderr, "Error: Coudln't open the input file.\n");
return (-1);
}
fprintf(stderr, "Error: Coudln't open the input file.\n");
return (-1);
}
if (avformat_alloc_output_context2(&out_ctx, NULL, NULL, out_path) < 0) {
fprintf(stderr, "Error: Couldn't create an output file.\n");
avformat_close_input(&in_ctx);
avformat_close_input(&in_ctx);
return (-1);
}
stream_map = prepare_streammap(in_ctx, out_ctx);
options = create_options_context(out_path);
if (!stream_map || !options || open_output_file_for_write(out_ctx, out_path, &options) != 0) {
destroy_context(in_ctx, out_ctx, options, stream_map);
return (-1);
}
write_to_output(in_ctx, out_ctx, stream_map, playable_duration);
destroy_context(in_ctx, out_ctx, options, stream_map);
return (-1);
}
write_to_output(in_ctx, out_ctx, stream_map, playable_duration);
destroy_context(in_ctx, out_ctx, options, stream_map);
return (0);
}

View File

@@ -10,25 +10,25 @@
int main(int argc, char **argv)
{
unsigned stream_count = 0;
unsigned subtitle_count = 0;
float playable_duration;
stream *streams;
unsigned stream_count = 0;
unsigned subtitle_count = 0;
float playable_duration;
stream *streams;
if (argc == 3 && !strcmp(argv[1], "info")) {
streams = get_track_info(argv[2], &stream_count, &subtitle_count);
free_streams(streams, stream_count);
}
else if (argc == 3 && !strcmp(argv[1], "subextr")) {
streams = extract_subtitles(argv[2], ".", &stream_count, &subtitle_count);
free_streams(streams, stream_count);
}
else if (argc == 4 && !strcmp(argv[1], "transmux"))
return (transmux(argv[2], argv[3], &playable_duration));
else
printf("\nUsage:\n\n\
%s INFO video_path - Test info prober\n\
%s subextr video_path - Test subtitle extractions\n\
%s transmux video_path m3u8_output_file - Test transmuxing\n", argv[0], argv[0], argv[0]);
return (0);
if (argc == 3 && !strcmp(argv[1], "info")) {
streams = get_track_info(argv[2], &stream_count, &subtitle_count);
free_streams(streams, stream_count);
}
else if (argc == 3 && !strcmp(argv[1], "subextr")) {
streams = extract_subtitles(argv[2], ".", &stream_count, &subtitle_count);
free_streams(streams, stream_count);
}
else if (argc == 4 && !strcmp(argv[1], "transmux"))
return (transmux(argv[2], argv[3], &playable_duration));
else
printf("\nUsage:\n\n\
%s INFO video_path - Test info prober\n\
%s subextr video_path - Test subtitle extractions\n\
%s transmux video_path m3u8_output_file - Test transmuxing\n", argv[0], argv[0], argv[0]);
return (0);
}