Commit 9cf4ed56 authored by Joseph Wallace's avatar Joseph Wallace

Probe SimpleBlocks to determine which clusters start with a keyframe.

parent 6e11db5d
...@@ -61,6 +61,12 @@ typedef enum ebml_chunk_type { ...@@ -61,6 +61,12 @@ typedef enum ebml_chunk_type {
EBML_CHUNK_CLUSTER_CONTINUE EBML_CHUNK_CLUSTER_CONTINUE
} ebml_chunk_type; } ebml_chunk_type;
typedef enum ebml_keyframe_status {
EBML_KEYFRAME_UNKNOWN = -1,
EBML_KEYFRAME_DOES_NOT_START_CLUSTER = 0,
EBML_KEYFRAME_STARTS_CLUSTER = 1
} ebml_keyframe_status;
typedef struct ebml_client_data_st ebml_client_data_t; typedef struct ebml_client_data_st ebml_client_data_t;
struct ebml_client_data_st { struct ebml_client_data_st {
...@@ -77,6 +83,7 @@ struct ebml_st { ...@@ -77,6 +83,7 @@ struct ebml_st {
unsigned long long copy_len; unsigned long long copy_len;
int cluster_start; int cluster_start;
ebml_keyframe_status cluster_starts_with_keyframe;
int flush_cluster; int flush_cluster;
int position; int position;
...@@ -473,7 +480,11 @@ static int ebml_read(ebml_t *ebml, char *buffer, int len, ebml_chunk_type *chunk ...@@ -473,7 +480,11 @@ static int ebml_read(ebml_t *ebml, char *buffer, int len, ebml_chunk_type *chunk
if (ebml->cluster_start == 0) { if (ebml->cluster_start == 0) {
/* new cluster is starting now */ /* new cluster is starting now */
if (ebml->cluster_starts_with_keyframe == EBML_KEYFRAME_STARTS_CLUSTER) {
/* Successfully found a keyframe in this cluster's video track */
*chunk_type = EBML_CHUNK_CLUSTER_START; *chunk_type = EBML_CHUNK_CLUSTER_START;
}
/* mark end of cluster */ /* mark end of cluster */
ebml->cluster_start = -1; ebml->cluster_start = -1;
...@@ -531,8 +542,11 @@ static int ebml_wrote(ebml_t *ebml, int len) ...@@ -531,8 +542,11 @@ static int ebml_wrote(ebml_t *ebml, int len)
int tag_length; int tag_length;
int value_length; int value_length;
int track_number_length;
unsigned long long payload_length; unsigned long long payload_length;
unsigned long long data_value; unsigned long long data_value;
unsigned long long track_number;
unsigned char flags;
int copy_state; int copy_state;
char *segment_id = "\x18\x53\x80\x67"; char *segment_id = "\x18\x53\x80\x67";
...@@ -541,6 +555,7 @@ static int ebml_wrote(ebml_t *ebml, int len) ...@@ -541,6 +555,7 @@ static int ebml_wrote(ebml_t *ebml, int len)
char *track_entry_id = "\xAE"; char *track_entry_id = "\xAE";
char *track_number_id = "\xD7"; char *track_number_id = "\xD7";
char *track_type_id = "\x83"; char *track_type_id = "\x83";
char *simple_block_id = "\xA3";
ebml->input_position += len; ebml->input_position += len;
end_of_buffer = ebml->input_buffer + ebml->input_position; end_of_buffer = ebml->input_buffer + ebml->input_position;
...@@ -585,7 +600,42 @@ static int ebml_wrote(ebml_t *ebml, int len) ...@@ -585,7 +600,42 @@ static int ebml_wrote(ebml_t *ebml, int len)
} }
if (tag_length > 1) { if (tag_length > 1) {
if (!memcmp(ebml->input_buffer + cursor, track_entry_id, 1)) { if (!memcmp(ebml->input_buffer + cursor, simple_block_id, 1)) {
/* Probe SimpleBlock header for the keyframe status */
if (ebml->cluster_starts_with_keyframe == EBML_KEYFRAME_UNKNOWN) {
track_number_length = ebml_parse_var_int(ebml->input_buffer + cursor + tag_length,
end_of_buffer, &track_number);
if (track_number_length == 0) {
/* Wait for more data */
processing = 0;
} else if (track_number_length < 0) {
return -1;
} else if (track_number == ebml->keyframe_track_number) {
/* this block belongs to the video track */
/* skip the 16-bit timecode for now, read the flags byte */
if (cursor + tag_length + track_number_length + 2 >= ebml->input_position) {
/* Wait for more data */
processing = 0;
} else {
flags = ebml->input_buffer[cursor + tag_length + track_number_length + 2];
if (flags & 0x80) {
/* "keyframe" flag is set */
ebml->cluster_starts_with_keyframe = EBML_KEYFRAME_STARTS_CLUSTER;
/* ICECAST_LOG_DEBUG("Found keyframe in track %hhu", track_number); */
} else {
ebml->cluster_starts_with_keyframe = EBML_KEYFRAME_DOES_NOT_START_CLUSTER;
/* ICECAST_LOG_DEBUG("Found non-keyframe in track %hhu", track_number); */
}
}
}
}
} else if (!memcmp(ebml->input_buffer + cursor, track_entry_id, 1)) {
/* Parse all TrackEntry children; reset the state */ /* Parse all TrackEntry children; reset the state */
payload_length = 0; payload_length = 0;
ebml->parsing_track_number = EBML_UNKNOWN; ebml->parsing_track_number = EBML_UNKNOWN;
...@@ -668,8 +718,9 @@ static int ebml_wrote(ebml_t *ebml, int len) ...@@ -668,8 +718,9 @@ static int ebml_wrote(ebml_t *ebml, int len)
/* The header has been fully read by now, publish its size. */ /* The header has been fully read by now, publish its size. */
ebml->header_size = ebml->header_position; ebml->header_size = ebml->header_position;
/* Mark this sync point */ /* Mark this potential sync point, prepare probe */
ebml->cluster_start = ebml->position; ebml->cluster_start = ebml->position;
ebml->cluster_starts_with_keyframe = EBML_KEYFRAME_UNKNOWN;
/* Buffer data to give us time to probe for keyframes, etc. */ /* Buffer data to give us time to probe for keyframes, etc. */
ebml->flush_cluster = 0; ebml->flush_cluster = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment