diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Chapter.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Chapter.java new file mode 100644 index 0000000..bf726ae --- /dev/null +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/Chapter.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2021 Taner Sener + * + * This file is part of FFmpegKit. + * + * FFmpegKit is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FFmpegKit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpegKit. If not, see . + */ + +package com.arthenica.ffmpegkit; + +import org.json.JSONObject; + +public class Chapter { + + /* KEYS */ + public static final String KEY_ID = "id"; + public static final String KEY_TIME_BASE = "time_base"; + public static final String KEY_START = "start"; + public static final String KEY_START_TIME = "start_time"; + public static final String KEY_END = "end"; + public static final String KEY_END_TIME = "end_time"; + public static final String KEY_TAGS = "tags"; + + private final JSONObject jsonObject; + + public Chapter(JSONObject jsonObject) { + this.jsonObject = jsonObject; + } + + public Long getId() { + return getNumberProperty(KEY_ID); + } + + public String getTimeBase() { + return getStringProperty(KEY_TIME_BASE); + } + + public Long getStart() { + return getNumberProperty(KEY_START); + } + + public String getStartTime() { + return getStringProperty(KEY_START_TIME); + } + + public Long getEnd() { + return getNumberProperty(KEY_END); + } + + public String getEndTime() { + return getStringProperty(KEY_END_TIME); + } + + public JSONObject getTags() { + return getProperties(KEY_TAGS); + } + + /** + * Returns the chapter property associated with the key. + * + * @param key property key + * @return chapter property as string or null if the key is not found + */ + public String getStringProperty(final String key) { + JSONObject chapterProperties = getAllProperties(); + if (chapterProperties == null) { + return null; + } + + if (chapterProperties.has(key)) { + return chapterProperties.optString(key); + } else { + return null; + } + } + + /** + * Returns the chapter property associated with the key. + * + * @param key property key + * @return chapter property as Long or null if the key is not found + */ + public Long getNumberProperty(String key) { + JSONObject chapterProperties = getAllProperties(); + if (chapterProperties == null) { + return null; + } + + if (chapterProperties.has(key)) { + return chapterProperties.optLong(key); + } else { + return null; + } + } + + /** + * Returns the chapter properties associated with the key. + * + * @param key properties key + * @return chapter properties as a JSONObject or null if the key is not found + */ + public JSONObject getProperties(String key) { + JSONObject chapterProperties = getAllProperties(); + if (chapterProperties == null) { + return null; + } + + return chapterProperties.optJSONObject(key); + } + + /** + * Returns all chapter properties defined. + * + * @return all chapter properties as a JSONObject or null if no properties are defined + */ + public JSONObject getAllProperties() { + return jsonObject; + } + +} diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeKit.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeKit.java index 2854287..9b9a6a3 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeKit.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFprobeKit.java @@ -52,6 +52,16 @@ public class FFprobeKit { private FFprobeKit() { } + /** + *

Builds the default command used to get media information for a file. + * + * @param path file path to use in the command + * @return default command arguments to get media information + */ + private static String[] defaultGetMediaInformationCommandArguments(final String path) { + return new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-show_chapters", "-i", path}; + } + /** *

Synchronously executes FFprobe with arguments provided. * @@ -249,7 +259,7 @@ public class FFprobeKit { * @return media information session created for this execution */ public static MediaInformationSession getMediaInformation(final String path) { - final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}); + final MediaInformationSession session = new MediaInformationSession(defaultGetMediaInformationCommandArguments(path)); FFmpegKitConfig.getMediaInformationExecute(session, AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); @@ -265,7 +275,7 @@ public class FFprobeKit { */ public static MediaInformationSession getMediaInformation(final String path, final int waitTimeout) { - final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}); + final MediaInformationSession session = new MediaInformationSession(defaultGetMediaInformationCommandArguments(path)); FFmpegKitConfig.getMediaInformationExecute(session, waitTimeout); @@ -284,7 +294,7 @@ public class FFprobeKit { */ public static MediaInformationSession getMediaInformationAsync(final String path, final ExecuteCallback executeCallback) { - final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback); + final MediaInformationSession session = new MediaInformationSession(defaultGetMediaInformationCommandArguments(path), executeCallback); FFmpegKitConfig.asyncGetMediaInformationExecute(session, AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); @@ -307,7 +317,7 @@ public class FFprobeKit { final ExecuteCallback executeCallback, final LogCallback logCallback, final int waitTimeout) { - final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, logCallback); + final MediaInformationSession session = new MediaInformationSession(defaultGetMediaInformationCommandArguments(path), executeCallback, logCallback); FFmpegKitConfig.asyncGetMediaInformationExecute(session, waitTimeout); @@ -328,7 +338,7 @@ public class FFprobeKit { public static MediaInformationSession getMediaInformationAsync(final String path, final ExecuteCallback executeCallback, final ExecutorService executorService) { - final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback); + final MediaInformationSession session = new MediaInformationSession(defaultGetMediaInformationCommandArguments(path), executeCallback); FFmpegKitConfig.asyncGetMediaInformationExecute(session, executorService, AbstractSession.DEFAULT_TIMEOUT_FOR_ASYNCHRONOUS_MESSAGES_IN_TRANSMIT); @@ -353,7 +363,7 @@ public class FFprobeKit { final LogCallback logCallback, final ExecutorService executorService, final int waitTimeout) { - final MediaInformationSession session = new MediaInformationSession(new String[]{"-v", "error", "-hide_banner", "-print_format", "json", "-show_format", "-show_streams", "-i", path}, executeCallback, logCallback); + final MediaInformationSession session = new MediaInformationSession(defaultGetMediaInformationCommandArguments(path), executeCallback, logCallback); FFmpegKitConfig.asyncGetMediaInformationExecute(session, executorService, waitTimeout); diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformation.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformation.java index 83d04a3..faf6674 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformation.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformation.java @@ -49,9 +49,15 @@ public class MediaInformation { */ private final List streams; - public MediaInformation(final JSONObject jsonObject, final List streams) { + /** + * Stores chapters. + */ + private final List chapters; + + public MediaInformation(final JSONObject jsonObject, final List streams, final List chapters) { this.jsonObject = jsonObject; this.streams = streams; + this.chapters = chapters; } /** @@ -135,6 +141,15 @@ public class MediaInformation { return streams; } + /** + * Returns all chapters. + * + * @return list of chapters + */ + public List getChapters() { + return chapters; + } + /** * Returns the media property associated with the key. * diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationJsonParser.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationJsonParser.java index 2d78e6c..45a9471 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationJsonParser.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/MediaInformationJsonParser.java @@ -34,6 +34,9 @@ import java.util.ArrayList; */ public class MediaInformationJsonParser { + public static final String KEY_STREAMS = "streams"; + public static final String KEY_CHAPTERS = "chapters"; + /** * Extracts MediaInformation from the given FFprobe json output. Note that this * method does not throw {@link JSONException} as {@link #fromWithError(String)} does and @@ -59,18 +62,27 @@ public class MediaInformationJsonParser { * @throws JSONException if a parsing error occurs */ public static MediaInformation fromWithError(final String ffprobeJsonOutput) throws JSONException { - JSONObject jsonObject = new JSONObject(ffprobeJsonOutput); - JSONArray streamArray = jsonObject.optJSONArray("streams"); + final JSONObject jsonObject = new JSONObject(ffprobeJsonOutput); + final JSONArray streamArray = jsonObject.optJSONArray(KEY_STREAMS); + final JSONArray chapterArray = jsonObject.optJSONArray(KEY_CHAPTERS); - ArrayList arrayList = new ArrayList<>(); + ArrayList streamList = new ArrayList<>(); for (int i = 0; streamArray != null && i < streamArray.length(); i++) { JSONObject streamObject = streamArray.optJSONObject(i); if (streamObject != null) { - arrayList.add(new StreamInformation(streamObject)); + streamList.add(new StreamInformation(streamObject)); + } + } + + ArrayList chapterList = new ArrayList<>(); + for (int i = 0; chapterArray != null && i < chapterArray.length(); i++) { + JSONObject chapterObject = chapterArray.optJSONObject(i); + if (chapterObject != null) { + chapterList.add(new Chapter(chapterObject)); } } - return new MediaInformation(jsonObject, arrayList); + return new MediaInformation(jsonObject, streamList, chapterList); } } diff --git a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StreamInformation.java b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StreamInformation.java index 487de30..45bd329 100644 --- a/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StreamInformation.java +++ b/android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/StreamInformation.java @@ -211,7 +211,7 @@ public class StreamInformation { /** * Returns all tags. * - * @return tags dictionary + * @return tags object */ public JSONObject getTags() { return getProperties(KEY_TAGS); diff --git a/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegKitTest.java b/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegKitTest.java index 24cbba8..29e16ad 100644 --- a/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegKitTest.java +++ b/android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegKitTest.java @@ -72,6 +72,85 @@ public class FFmpegKitTest { " }\n" + " }\n" + " ],\n" + + " \"chapters\": [\n" + + " {\n" + + " \"id\": 0,\n" + + " \"time_base\": \"1/22050\",\n" + + " \"start\": 0,\n" + + " \"start_time\": \"0.000000\",\n" + + " \"end\": 11158238,\n" + + " \"end_time\": \"506.042540\",\n" + + " \"tags\": {\n" + + " \"title\": \"1 Laying Plans - 2 Waging War\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"id\": 1,\n" + + " \"time_base\": \"1/22050\",\n" + + " \"start\": 11158238,\n" + + " \"start_time\": \"506.042540\",\n" + + " \"end\": 21433051,\n" + + " \"end_time\": \"972.020454\",\n" + + " \"tags\": {\n" + + " \"title\": \"3 Attack By Stratagem - 4 Tactical Dispositions\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"id\": 2,\n" + + " \"time_base\": \"1/22050\",\n" + + " \"start\": 21433051,\n" + + " \"start_time\": \"972.020454\",\n" + + " \"end\": 35478685,\n" + + " \"end_time\": \"1609.010658\",\n" + + " \"tags\": {\n" + + " \"title\": \"5 Energy - 6 Weak Points and Strong\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"id\": 3,\n" + + " \"time_base\": \"1/22050\",\n" + + " \"start\": 35478685,\n" + + " \"start_time\": \"1609.010658\",\n" + + " \"end\": 47187043,\n" + + " \"end_time\": \"2140.001950\",\n" + + " \"tags\": {\n" + + " \"title\": \"7 Maneuvering - 8 Variation in Tactics\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"id\": 4,\n" + + " \"time_base\": \"1/22050\",\n" + + " \"start\": 47187043,\n" + + " \"start_time\": \"2140.001950\",\n" + + " \"end\": 66635594,\n" + + " \"end_time\": \"3022.022404\",\n" + + " \"tags\": {\n" + + " \"title\": \"9 The Army on the March - 10 Terrain\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"id\": 5,\n" + + " \"time_base\": \"1/22050\",\n" + + " \"start\": 66635594,\n" + + " \"start_time\": \"3022.022404\",\n" + + " \"end\": 83768105,\n" + + " \"end_time\": \"3799.007029\",\n" + + " \"tags\": {\n" + + " \"title\": \"11 The Nine Situations\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"id\": 6,\n" + + " \"time_base\": \"1/22050\",\n" + + " \"start\": 83768105,\n" + + " \"start_time\": \"3799.007029\",\n" + + " \"end\": 95659008,\n" + + " \"end_time\": \"4338.277007\",\n" + + " \"tags\": {\n" + + " \"title\": \"12 The Attack By Fire - 13 The Use of Spies\"\n" + + " }\n" + + " }\n" + + " ],\n" + " \"format\": {\n" + " \"filename\": \"sample.mp3\",\n" + " \"nb_streams\": 1,\n" + @@ -459,6 +538,11 @@ public class FFmpegKitTest { Assert.assertNotNull(mediaInformation.getStreams()); Assert.assertEquals(1, mediaInformation.getStreams().size()); assertAudioStream(mediaInformation.getStreams().get(0), 0L, "mp3", "MP3 (MPEG audio layer 3)", "44100", "stereo", "fltp", "320000"); + + Assert.assertNotNull(mediaInformation.getChapters()); + Assert.assertEquals(7, mediaInformation.getChapters().size()); + assertChapter(mediaInformation.getChapters().get(0), 0L, "1/22050", 0L, "0.000000", 11158238L, "506.042540"); + assertChapter(mediaInformation.getChapters().get(1), 1L, "1/22050", 11158238L, "506.042540", 21433051L, "972.020454"); } @Test @@ -743,4 +827,18 @@ public class FFmpegKitTest { Assert.assertEquals(codecTimeBase, streamInformation.getCodecTimeBase()); } + private void assertChapter(Chapter chapter, Long id, String timeBase, Long start, String startTime, Long end, String endTime) { + Assert.assertEquals(id, chapter.getId()); + Assert.assertEquals(timeBase, chapter.getTimeBase()); + + Assert.assertEquals(start, chapter.getStart()); + Assert.assertEquals(startTime, chapter.getStartTime()); + + Assert.assertEquals(end, chapter.getEnd()); + Assert.assertEquals(endTime, chapter.getEndTime()); + + Assert.assertNotNull(chapter.getTags()); + Assert.assertEquals(1, chapter.getTags().length()); + } + } diff --git a/apple/src/Chapter.h b/apple/src/Chapter.h new file mode 100644 index 0000000..f85e2b7 --- /dev/null +++ b/apple/src/Chapter.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021 Taner Sener + * + * This file is part of FFmpegKit. + * + * FFmpegKit is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FFmpegKit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpegKit. If not, see . + */ + +#ifndef FFMPEG_KIT_CHAPTER_H +#define FFMPEG_KIT_CHAPTER_H + +#import + +extern NSString* const ChapterKeyId; +extern NSString* const ChapterKeyTimeBase; +extern NSString* const ChapterKeyStart; +extern NSString* const ChapterKeyStartTime; +extern NSString* const ChapterKeyEnd; +extern NSString* const ChapterKeyEndTime; +extern NSString* const ChapterKeyTags; + +/** + * Chapter class. + */ +@interface Chapter : NSObject + +- (instancetype)init:(NSDictionary*)chapterDictionary; + +- (NSNumber*)getId; + +- (NSString*)getTimeBase; + +- (NSNumber*)getStart; + +- (NSString*)getStartTime; + +- (NSNumber*)getEnd; + +- (NSString*)getEndTime; + +- (NSDictionary*)getTags; + +/** + * Returns the chapter property associated with the key. + * + * @return chapter property as string or nil if the key is not found + */ +- (NSString*)getStringProperty:(NSString*)key; + +/** + * Returns the chapter property associated with the key. + * + * @return chapter property as number or nil if the key is not found + */ +- (NSNumber*)getNumberProperty:(NSString*)key; + +/** + * Returns the chapter properties associated with the key. + * + * @return chapter properties in a dictionary or nil if the key is not found +*/ +- (NSDictionary*)getProperties:(NSString*)key; + +/** + * Returns all chapter properties defined. + * + * @return all chapter properties in a dictionary or nil if no properties are defined +*/ +- (NSDictionary*)getAllProperties; + +@end + +#endif // FFMPEG_KIT_CHAPTER_H diff --git a/apple/src/Chapter.m b/apple/src/Chapter.m new file mode 100644 index 0000000..30baf06 --- /dev/null +++ b/apple/src/Chapter.m @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021 Taner Sener + * + * This file is part of FFmpegKit. + * + * FFmpegKit is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FFmpegKit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpegKit. If not, see . + */ + +#import "Chapter.h" + +NSString* const ChapterKeyId = @"id"; +NSString* const ChapterKeyTimeBase = @"time_base"; +NSString* const ChapterKeyStart = @"start"; +NSString* const ChapterKeyStartTime = @"start_time"; +NSString* const ChapterKeyEnd = @"end"; +NSString* const ChapterKeyEndTime = @"end_time"; +NSString* const ChapterKeyTags = @"tags"; + +@implementation Chapter { + + /** + * Stores all properties. + */ + NSDictionary *dictionary; + +} + +- (instancetype)init:(NSDictionary*)chapterDictionary { + self = [super init]; + if (self) { + dictionary = chapterDictionary; + } + + return self; +} + +- (NSNumber*)getId { + return [self getNumberProperty:ChapterKeyId]; +} + +- (NSString*)getTimeBase { + return [self getStringProperty:ChapterKeyTimeBase]; +} + +- (NSNumber*)getStart { + return [self getNumberProperty:ChapterKeyStart]; +} + +- (NSString*)getStartTime { + return [self getStringProperty:ChapterKeyStartTime]; +} + +- (NSNumber*)getEnd { + return [self getNumberProperty:ChapterKeyEnd]; +} + +- (NSString*)getEndTime { + return [self getStringProperty:ChapterKeyEndTime]; +} + +- (NSDictionary*)getTags { + return [self getProperties:ChapterKeyTags]; +} + +- (NSString*)getStringProperty:(NSString*)key { + NSDictionary* allProperties = [self getAllProperties]; + if (allProperties == nil) { + return nil; + } + + return allProperties[key]; +} + +- (NSNumber*)getNumberProperty:(NSString*)key { + NSDictionary* mediaProperties = [self getAllProperties]; + if (mediaProperties == nil) { + return nil; + } + + return mediaProperties[key]; +} + +- (NSDictionary*)getProperties:(NSString*)key { + NSDictionary* allProperties = [self getAllProperties]; + if (allProperties == nil) { + return nil; + } + + return allProperties[key]; +} + +- (NSDictionary*)getAllProperties { + return dictionary; +} + +@end diff --git a/apple/src/FFprobeKit.m b/apple/src/FFprobeKit.m index 6611b0e..cc013ea 100644 --- a/apple/src/FFprobeKit.m +++ b/apple/src/FFprobeKit.m @@ -28,6 +28,10 @@ [FFmpegKitConfig class]; } ++ (NSArray*)defaultGetMediaInformationCommandArguments:(NSString*)path { + return [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-show_chapters", @"-i", path, nil]; +} + + (FFprobeSession*)executeWithArguments:(NSArray*)arguments { FFprobeSession* session = [[FFprobeSession alloc] init:arguments]; [FFmpegKitConfig ffprobeExecute:session]; @@ -89,42 +93,42 @@ } + (MediaInformationSession*)getMediaInformation:(NSString*)path { - NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path]; MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments]; [FFmpegKitConfig getMediaInformationExecute:session withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit]; return session; } + (MediaInformationSession*)getMediaInformation:(NSString*)path withTimeout:(int)waitTimeout { - NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path]; MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments]; [FFmpegKitConfig getMediaInformationExecute:session withTimeout:waitTimeout]; return session; } + (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteCallback:(ExecuteCallback)executeCallback { - NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path]; MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteCallback:executeCallback]; [FFmpegKitConfig asyncGetMediaInformationExecute:session withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit]; return session; } + (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteCallback:(ExecuteCallback)executeCallback withLogCallback:(LogCallback)logCallback withTimeout:(int)waitTimeout { - NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path]; MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteCallback:executeCallback withLogCallback:logCallback]; [FFmpegKitConfig asyncGetMediaInformationExecute:session withTimeout:waitTimeout]; return session; } + (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteCallback:(ExecuteCallback)executeCallback onDispatchQueue:(dispatch_queue_t)queue { - NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path]; MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteCallback:executeCallback]; [FFmpegKitConfig asyncGetMediaInformationExecute:session onDispatchQueue:queue withTimeout:AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit]; return session; } + (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withExecuteCallback:(ExecuteCallback)executeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout { - NSArray* arguments = [[NSArray alloc] initWithObjects:@"-v", @"error", @"-hide_banner", @"-print_format", @"json", @"-show_format", @"-show_streams", @"-i", path, nil]; + NSArray* arguments = [FFprobeKit defaultGetMediaInformationCommandArguments:path]; MediaInformationSession* session = [[MediaInformationSession alloc] init:arguments withExecuteCallback:executeCallback]; [FFmpegKitConfig asyncGetMediaInformationExecute:session onDispatchQueue:queue withTimeout:waitTimeout]; return session; diff --git a/apple/src/Makefile.am b/apple/src/Makefile.am index cdc9009..2a2d6d8 100644 --- a/apple/src/Makefile.am +++ b/apple/src/Makefile.am @@ -6,6 +6,7 @@ libffmpegkit_la_SOURCES = \ AbstractSession.m \ ArchDetect.m \ AtomicLong.m \ + Chapter.m \ FFmpegKit.m \ FFmpegKitConfig.m \ FFmpegSession.m \ @@ -35,6 +36,7 @@ include_HEADERS = \ AbstractSession.h \ ArchDetect.h \ AtomicLong.h \ + Chapter.h \ ExecuteCallback.h \ FFmpegKit.h \ FFmpegKitConfig.h \ diff --git a/apple/src/Makefile.in b/apple/src/Makefile.in index d14103d..600e946 100644 --- a/apple/src/Makefile.in +++ b/apple/src/Makefile.in @@ -134,18 +134,18 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) libffmpegkit_la_DEPENDENCIES = am__libffmpegkit_la_SOURCES_DIST = AbstractSession.m ArchDetect.m \ - AtomicLong.m FFmpegKit.m FFmpegKitConfig.m FFmpegSession.m \ - FFprobeKit.m FFprobeSession.m Log.m MediaInformation.m \ - MediaInformationJsonParser.m MediaInformationSession.m \ - Packages.m ReturnCode.m Statistics.m StreamInformation.m \ - ffmpegkit_exception.m fftools_cmdutils.c fftools_ffmpeg.c \ - fftools_ffmpeg_filter.c fftools_ffmpeg_hw.c \ + AtomicLong.m Chapter.m FFmpegKit.m FFmpegKitConfig.m \ + FFmpegSession.m FFprobeKit.m FFprobeSession.m Log.m \ + MediaInformation.m MediaInformationJsonParser.m \ + MediaInformationSession.m Packages.m ReturnCode.m Statistics.m \ + StreamInformation.m ffmpegkit_exception.m fftools_cmdutils.c \ + fftools_ffmpeg.c fftools_ffmpeg_filter.c fftools_ffmpeg_hw.c \ fftools_ffmpeg_opt.c fftools_ffprobe.c \ fftools_ffmpeg_videotoolbox.c @FFMPEGKIT_VIDEOTOOLBOX_TRUE@am__objects_1 = libffmpegkit_la-fftools_ffmpeg_videotoolbox.lo am_libffmpegkit_la_OBJECTS = libffmpegkit_la-AbstractSession.lo \ libffmpegkit_la-ArchDetect.lo libffmpegkit_la-AtomicLong.lo \ - libffmpegkit_la-FFmpegKit.lo \ + libffmpegkit_la-Chapter.lo libffmpegkit_la-FFmpegKit.lo \ libffmpegkit_la-FFmpegKitConfig.lo \ libffmpegkit_la-FFmpegSession.lo libffmpegkit_la-FFprobeKit.lo \ libffmpegkit_la-FFprobeSession.lo libffmpegkit_la-Log.lo \ @@ -189,6 +189,7 @@ am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/libffmpegkit_la-AbstractSession.Plo \ ./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo \ ./$(DEPDIR)/libffmpegkit_la-AtomicLong.Plo \ + ./$(DEPDIR)/libffmpegkit_la-Chapter.Plo \ ./$(DEPDIR)/libffmpegkit_la-FFmpegKit.Plo \ ./$(DEPDIR)/libffmpegkit_la-FFmpegKitConfig.Plo \ ./$(DEPDIR)/libffmpegkit_la-FFmpegSession.Plo \ @@ -401,8 +402,8 @@ top_srcdir = @top_srcdir@ lib_LTLIBRARIES = libffmpegkit.la libffmpegkit_la_LIBADD = @FFMPEG_FRAMEWORKS@ libffmpegkit_la_SOURCES = AbstractSession.m ArchDetect.m AtomicLong.m \ - FFmpegKit.m FFmpegKitConfig.m FFmpegSession.m FFprobeKit.m \ - FFprobeSession.m Log.m MediaInformation.m \ + Chapter.m FFmpegKit.m FFmpegKitConfig.m FFmpegSession.m \ + FFprobeKit.m FFprobeSession.m Log.m MediaInformation.m \ MediaInformationJsonParser.m MediaInformationSession.m \ Packages.m ReturnCode.m Statistics.m StreamInformation.m \ ffmpegkit_exception.m fftools_cmdutils.c fftools_ffmpeg.c \ @@ -412,6 +413,7 @@ include_HEADERS = \ AbstractSession.h \ ArchDetect.h \ AtomicLong.h \ + Chapter.h \ ExecuteCallback.h \ FFmpegKit.h \ FFmpegKitConfig.h \ @@ -521,6 +523,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-AbstractSession.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-AtomicLong.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-Chapter.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-FFmpegKit.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-FFmpegKitConfig.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libffmpegkit_la-FFmpegSession.Plo@am__quote@ # am--include-marker @@ -667,6 +670,13 @@ libffmpegkit_la-AtomicLong.lo: AtomicLong.m @AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-AtomicLong.lo `test -f 'AtomicLong.m' || echo '$(srcdir)/'`AtomicLong.m +libffmpegkit_la-Chapter.lo: Chapter.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-Chapter.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-Chapter.Tpo -c -o libffmpegkit_la-Chapter.lo `test -f 'Chapter.m' || echo '$(srcdir)/'`Chapter.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-Chapter.Tpo $(DEPDIR)/libffmpegkit_la-Chapter.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='Chapter.m' object='libffmpegkit_la-Chapter.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -c -o libffmpegkit_la-Chapter.lo `test -f 'Chapter.m' || echo '$(srcdir)/'`Chapter.m + libffmpegkit_la-FFmpegKit.lo: FFmpegKit.m @am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libffmpegkit_la_OBJCFLAGS) $(OBJCFLAGS) -MT libffmpegkit_la-FFmpegKit.lo -MD -MP -MF $(DEPDIR)/libffmpegkit_la-FFmpegKit.Tpo -c -o libffmpegkit_la-FFmpegKit.lo `test -f 'FFmpegKit.m' || echo '$(srcdir)/'`FFmpegKit.m @am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libffmpegkit_la-FFmpegKit.Tpo $(DEPDIR)/libffmpegkit_la-FFmpegKit.Plo @@ -922,6 +932,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/libffmpegkit_la-AbstractSession.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-AtomicLong.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-Chapter.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegKit.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegKitConfig.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegSession.Plo @@ -991,6 +1002,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libffmpegkit_la-AbstractSession.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-ArchDetect.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-AtomicLong.Plo + -rm -f ./$(DEPDIR)/libffmpegkit_la-Chapter.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegKit.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegKitConfig.Plo -rm -f ./$(DEPDIR)/libffmpegkit_la-FFmpegSession.Plo diff --git a/apple/src/MediaInformation.h b/apple/src/MediaInformation.h index 20813cf..6d2ea86 100644 --- a/apple/src/MediaInformation.h +++ b/apple/src/MediaInformation.h @@ -21,6 +21,7 @@ #define FFMPEG_KIT_MEDIA_INFORMATION_H #import +#import "Chapter.h" #import "StreamInformation.h" extern NSString* const MediaKeyMediaProperties; @@ -38,7 +39,7 @@ extern NSString* const MediaKeyTags; */ @interface MediaInformation : NSObject -- (instancetype)init:(NSDictionary*)mediaDictionary withStreams:(NSArray*)streams; +- (instancetype)init:(NSDictionary*)mediaDictionary withStreams:(NSArray*)streams withChapters:(NSArray*)chapters; /** * Returns file name. @@ -103,6 +104,13 @@ extern NSString* const MediaKeyTags; */ - (NSArray*)getStreams; +/** + * Returns all chapters. + * + * @return chapters array + */ +- (NSArray*)getChapters; + /** * Returns the media property associated with the key. * diff --git a/apple/src/MediaInformation.m b/apple/src/MediaInformation.m index c8ba7a9..a9211db 100644 --- a/apple/src/MediaInformation.m +++ b/apple/src/MediaInformation.m @@ -41,13 +41,19 @@ NSString* const MediaKeyTags = @"tags"; */ NSArray *streamArray; + /** + * Stores chapters. + */ + NSArray *chapterArray; + } -- (instancetype)init:(NSDictionary*)mediaDictionary withStreams:(NSArray*)streams{ +- (instancetype)init:(NSDictionary*)mediaDictionary withStreams:(NSArray*)streams withChapters:(NSArray*)chapters{ self = [super init]; if (self) { dictionary = mediaDictionary; streamArray = streams; + chapterArray = chapters; } return self; @@ -89,6 +95,10 @@ NSString* const MediaKeyTags = @"tags"; return streamArray; } +- (NSArray*)getChapters { + return chapterArray; +} + - (NSString*)getStringProperty:(NSString*)key { NSDictionary* mediaProperties = [self getMediaProperties]; if (mediaProperties == nil) { diff --git a/apple/src/MediaInformationJsonParser.m b/apple/src/MediaInformationJsonParser.m index e7fa171..c7fe7cb 100644 --- a/apple/src/MediaInformationJsonParser.m +++ b/apple/src/MediaInformationJsonParser.m @@ -19,6 +19,9 @@ #import "MediaInformationJsonParser.h" +NSString* const MediaInformationJsonParserKeyStreams = @"streams"; +NSString* const MediaInformationJsonParserKeyChapters = @"chapters"; + @implementation MediaInformationJsonParser + (MediaInformation*)from:(NSString*)ffprobeJsonOutput { @@ -40,14 +43,21 @@ return nil; } - NSArray* array = [jsonDictionary objectForKey:@"streams"]; + NSArray* jsonStreamArray = [jsonDictionary objectForKey:MediaInformationJsonParserKeyStreams]; NSMutableArray *streamArray = [[NSMutableArray alloc] init]; - for(int i = 0; i