Skip to content

Commit

Permalink
Merge pull request #6314 from ant-media/support-scheduling-playlist
Browse files Browse the repository at this point in the history
Add duration rest method to get the duration of an stream URL
  • Loading branch information
mekya committed May 6, 2024
2 parents b3ad4cd + 891e600 commit ddb020a
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 710 deletions.
9 changes: 9 additions & 0 deletions src/main/java/io/antmedia/datastore/db/types/Broadcast.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ public static class PlayListItem
{
String streamUrl;
String type;
String name;

/**
* Duration of this item in milliseconds. It's calculated by Ant Media Server
Expand Down Expand Up @@ -261,6 +262,14 @@ public void setDurationInMs(long durationInMs) {
this.durationInMs = durationInMs;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}


Expand Down
23 changes: 20 additions & 3 deletions src/main/java/io/antmedia/muxer/Muxer.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import java.util.regex.Pattern;

import io.antmedia.FFmpegUtilities;
import io.antmedia.rest.RestServiceBase;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.bytedeco.ffmpeg.avcodec.AVBSFContext;
import org.bytedeco.ffmpeg.avcodec.AVBitStreamFilter;
Expand Down Expand Up @@ -1222,24 +1224,39 @@ public static long getDurationInMs(File f, String streamId) {
}


/**
*
* @param url
* @param streamId
* @return
* -1 if duration is not available in the stream
* -2 if input is not opened
* -3 if stream info is not found
*
*/
public static long getDurationInMs(String url, String streamId) {
AVFormatContext inputFormatContext = avformat.avformat_alloc_context();
int ret;
if (streamId != null) {
streamId = streamId.replaceAll("[\n\r\t]", "_");
streamId = RestServiceBase.replaceCharsForSecurity(streamId);
}

if (url != null) {
url = RestServiceBase.replaceCharsForSecurity(url);
}

if (avformat_open_input(inputFormatContext, url, null, (AVDictionary)null) < 0)
{
loggerStatic.info("cannot open input context for duration for stream: {} for file:{}", streamId, url);
avformat_close_input(inputFormatContext);
return -1L;
return -2L;
}

ret = avformat_find_stream_info(inputFormatContext, (AVDictionary)null);
if (ret < 0) {
loggerStatic.info("Could not find stream information for stream: {} for file:{}", streamId, url);
avformat_close_input(inputFormatContext);
return -1L;
return -3L;
}
long durationInMS = -1;
if (inputFormatContext.duration() != AV_NOPTS_VALUE)
Expand Down
33 changes: 33 additions & 0 deletions src/main/java/io/antmedia/rest/BroadcastRestService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.antmedia.cluster.IClusterNotifier;
import io.antmedia.cluster.IStreamInfo;
import io.antmedia.datastore.db.types.Broadcast;
import io.antmedia.datastore.db.types.Broadcast.PlayListItem;
import io.antmedia.datastore.db.types.ConferenceRoom;
import io.antmedia.datastore.db.types.Endpoint;
import io.antmedia.datastore.db.types.Subscriber;
Expand All @@ -24,6 +25,7 @@
import io.antmedia.ipcamera.OnvifCamera;
import io.antmedia.muxer.IAntMediaStreamHandler;
import io.antmedia.muxer.MuxAdaptor;
import io.antmedia.muxer.Muxer;
import io.antmedia.rest.model.BasicStreamInfo;
import io.antmedia.rest.model.Result;
import io.antmedia.security.ITokenService;
Expand Down Expand Up @@ -362,6 +364,37 @@ public Result updateBroadcast(@Parameter(description="Broadcast id", required =
}
return result;
}

@Operation(description = "Gets the durations of the stream url in milliseconds",
responses = {
@ApiResponse(responseCode = "200", description = "If operation is successful, duration will be in dataId field and success field is true. "
+ "If it's failed, errorId has the error code(-1: duration is not available, -2: url is not opened, -3: cannot get stream info) and success field is false",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = Result.class)
))
}
)

@GET
@Consumes(MediaType.APPLICATION_JSON)
@Path("/duration")
@Produces(MediaType.APPLICATION_JSON)
public Result getDuration(@Parameter(description="Url of the stream that its duration will be returned", required=true) @QueryParam("url") String url) {
Result result = new Result(false);
if (StringUtils.isNotBlank(url)) {
long durationInMs = Muxer.getDurationInMs(url,null);
if (durationInMs >= 0) {
result.setSuccess(true);
result.setDataId(Long.toString(durationInMs));
}
else {
result.setErrorId((int)durationInMs);
}
}

return result;
}


@Operation(description = "Seeks the playing stream source, vod or playlist on the fly. It accepts seekTimeMs parameter in milliseconds")
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/io/antmedia/rest/RestServiceBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@

public abstract class RestServiceBase {

private static final String REPLACE_CHARS_FOR_SECURITY = "[\n\r]";
public static final String REPLACE_CHARS_FOR_SECURITY = "[\n\r]";

public class BroadcastStatistics {

Expand Down Expand Up @@ -2218,5 +2218,9 @@ public Result importVoDs(String directory) {
public Result unlinksVoD(String directory) {
return getApplication().unlinksVoD(directory);
}

public static String replaceCharsForSecurity(String value) {
return value.replaceAll(REPLACE_CHARS_FOR_SECURITY, "_");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,23 @@ public void testUpdatePlayListItemDuration() {
}


@Test
public void testGetDuration() {

Result result = restServiceReal.getDuration(StreamSchedularUnitTest.VALID_MP4_URL);
assertEquals(15045, Integer.valueOf(result.getDataId()).intValue());
assertTrue(result.isSuccess());


result = restServiceReal.getDuration(StreamSchedularUnitTest.INVALID_MP4_URL);
assertEquals(-2, Integer.valueOf(result.getErrorId()).intValue());
assertFalse(result.isSuccess());

result = restServiceReal.getDuration(null);
assertFalse(result.isSuccess());

}


/**
* These tests should be run with stalker db
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ public void testCreatePlaylist() {
playlist.setType(AntMediaApplicationAdapter.PLAY_LIST);
playlist.setPlayListItemList(broadcastList);



StatsCollector monitor = mock(StatsCollector.class);

Expand Down Expand Up @@ -308,6 +309,8 @@ public void testEditPlaylist() {

//create a broadcast
PlayListItem broadcastItem1 = new PlayListItem();
broadcastItem1.setName("name");
assertEquals("name", broadcastItem1.getName());

//create a broadcast
PlayListItem broadcastItem2 = new PlayListItem();
Expand Down
Loading

0 comments on commit ddb020a

Please sign in to comment.