diff --git a/CMakeLists.txt b/CMakeLists.txt index 44d0522..5261463 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ include_directories(include) add_library(transcoder SHARED src/helper.c src/subtitles.c - src/info.c) + src/info.c src/path_helper.c) set_property(TARGET transcoder PROPERTY C_STANDARD 11) target_link_libraries(transcoder diff --git a/include/path_helper.h b/include/path_helper.h new file mode 100644 index 0000000..ce48e24 --- /dev/null +++ b/include/path_helper.h @@ -0,0 +1,9 @@ +// +// Created by anonymus-raccoon on 12/29/19. +// + +#pragma once + +char *path_getfolder(const char *path); + +char *get_extension_from_codec(char *codec); \ No newline at end of file diff --git a/include/transcoder.h b/include/transcoder.h index d55ae68..c96e887 100644 --- a/include/transcoder.h +++ b/include/transcoder.h @@ -11,4 +11,6 @@ //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. API stream *extract_subtitles(char *path, const char *out_path, unsigned *stream_count, unsigned *subtitle_count); -API void free_memory(stream *streamsPtr); \ No newline at end of file +void destroy_stream(stream *s); + +API void free_streams(stream *streamsPtr, int count); \ No newline at end of file diff --git a/src/helper.c b/src/helper.c index 9ef14b5..f6ddf62 100644 --- a/src/helper.c +++ b/src/helper.c @@ -64,7 +64,21 @@ void process_packet(AVPacket *pkt, AVStream *in_stream, AVStream *out_stream) pkt->pos = -1; } -void free_memory(stream *stream_ptr) +void destroy_stream(stream *s) { - free(stream_ptr); + 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); } \ No newline at end of file diff --git a/src/path_helper.c b/src/path_helper.c new file mode 100644 index 0000000..1154c7b --- /dev/null +++ b/src/path_helper.c @@ -0,0 +1,51 @@ +// +// Created by anonymus-raccoon on 12/29/19. +// + +#include +#include +#include + +char *strrnchr(const char *str, int c, int occ_to_skip) +{ + 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); +} + +char *path_getfolder(const char *path) +{ + char *start; + char *end; + char *folder; + + start = strrnchr(path, '/', 1); + end = strrchr(path, '/'); + if (!end) + return (NULL); + folder = strndup(start, end - start); + return (folder); +} + +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); + } +} \ No newline at end of file diff --git a/src/subtitles.c b/src/subtitles.c index 84671cd..a0d85a6 100644 --- a/src/subtitles.c +++ b/src/subtitles.c @@ -5,45 +5,44 @@ #include "stream.h" #include "helper.h" #include "compatibility.h" +#include "path_helper.h" #include #include #include #include +#include int get_subtitle_data(stream *substream, AVStream *in_stream, const char *folder_name, const char *out_path) { AVDictionaryEntry *languageptr = av_dict_get(in_stream->metadata, "language", NULL, 0); - char *extension; char *codec = strdup(avcodec_get_name(in_stream->codecpar->codec_id)); + char *extension = get_extension_from_codec(codec); + char *folder_path; - if (!codec) - return (-1); - if (!strcmp(codec, "subrip")) - extension = ".srt"; - else if (!strcmp(codec, "ass")) - extension = ".ass"; - else { - printf("Unsupported subtitle codec: %s.\n", codec); - free(codec); - return (-1); - } + if (!extension) + return (-1); *substream = (stream) { NULL, - languageptr ? languageptr->value : NULL, + languageptr ? strdup(languageptr->value) : NULL, codec, in_stream->disposition & AV_DISPOSITION_DEFAULT, in_stream->disposition & AV_DISPOSITION_FORCED, NULL }; - asprintf(&substream->path, "%s/%s", out_path, substream->language); - if (!substream->path || kmkdir(substream->path, 0733) < 0) - return (-1); + asprintf(&folder_path, "%s/%s", out_path, substream->language); + if (!folder_path) + return (-1); + if (kmkdir(folder_path, 0733) < 0) { + free(folder_path); + return (-1); + } asprintf(&substream->path, "%s/%s.%s%s%s%s", substream->path, folder_name, substream->language, substream->is_default ? ".default" : "", substream->is_forced ? ".forced" : "", extension); + free(folder_path); if (!substream->path) return (-1); return (0); @@ -110,42 +109,55 @@ void finish_up(AVFormatContext *int_ctx, AVFormatContext **output_list, unsigned free(output_list); } +int split_inputfile(AVFormatContext *int_ctx, AVFormatContext **output_list, stream *streams, char *path, const char *out_path) +{ + int subcount = 0; + char *folder_name = path_getfolder(path); + + if (!folder_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, folder_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(folder_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; - char *folder_name = strchr(path, '/'); - char *p; + stream *streams; - if (!folder_name && (folder_name = strdup(folder_name))) - return (NULL); - p = strchr(folder_name, '.'); - if (p) - *p = '\0'; if (open_input_context(&int_ctx, path) != 0) - return (NULL); + return (NULL); *stream_count = int_ctx->nb_streams; - *subtitle_count = 0; - streams = malloc(sizeof(stream) * *stream_count); + streams = calloc(sizeof(stream), *stream_count); output_list = malloc(sizeof(AVFormatContext *) * *stream_count); - if (!streams || !output_list) - return (NULL); - for (unsigned int i = 0; i < *stream_count; 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, folder_name, out_path) == 0) { - if (copy_subtitle_stream(output_list[i], streams + i, int_ctx, in_stream) == 0) { - *subtitle_count += 1; - continue; - } - } - } - streams[i] = NULLSTREAM; - output_list[i] = NULL; - } - write_data(int_ctx, output_list, *stream_count); - finish_up(int_ctx, output_list, *stream_count); - return (streams); + 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 = 0; + if (streams) + free_streams(streams, (int)*stream_count); + if (output_list) + free(output_list); + return (NULL); } diff --git a/tests/test_main.c b/tests/test_main.c index 9bbe0be..656697a 100644 --- a/tests/test_main.c +++ b/tests/test_main.c @@ -3,15 +3,22 @@ // #include +#include #include "transcoder.h" +#include "stream.h" int main(int argc, char **argv) { unsigned stream_count = 0; unsigned subtitle_count = 0; + stream *streams; - if (argc == 3 && !strcmp(argv[1], "es")) - extract_subtitles(argv[2], "./", &stream_count, &subtitle_count); + if (argc == 3 && !strcmp(argv[1], "subextract")) { + streams = extract_subtitles(argv[2], ".", &stream_count, &subtitle_count); + free_streams(streams, stream_count); + } else + printf("\nUsage:\n\n\ + %s subextr video_path - Test subtitle extractions\n", argv[0]); return (0); } \ No newline at end of file