This source file includes following definitions.
- iso_progressive_read_thread
- main
#include <gpac/tools.h>
#include <gpac/isomedia.h>
#include <gpac/thread.h>
#define BUFFER_BLOCK_SIZE 1000
#define MAX_BUFFER_SIZE 200000
typedef enum {
ERROR,
RUNNING,
EOS
} state_t;
typedef struct iso_progressive_reader {
u8 *data;
u32 data_size;
u32 valid_data_size;
char data_url[256];
GF_ISOFile *movie;
GF_Mutex *mutex;
volatile state_t state;
u32 track_id;
} ISOProgressiveReader;
static u32 iso_progressive_read_thread(void *param)
{
ISOProgressiveReader *reader = (ISOProgressiveReader *)param;
u32 track_number;
GF_ISOSample *iso_sample;
u32 samples_processed;
u32 sample_index;
u32 sample_count;
samples_processed = 0;
sample_count = 0;
track_number = 0;
sample_index = 1;
while (reader->state != ERROR) {
if (reader->movie) {
gf_mx_p(reader->mutex);
if (track_number == 0) {
track_number = gf_isom_get_track_by_id(reader->movie, reader->track_id);
}
if (track_number != 0) {
u32 new_sample_count;
u32 di;
new_sample_count = gf_isom_get_sample_count(reader->movie, track_number);
if (new_sample_count > sample_count) {
fprintf(stdout, "Found %d new samples (total: %d)\n", new_sample_count - sample_count, new_sample_count);
if (sample_count == 0) {
sample_count = new_sample_count;
}
}
if (sample_count == 0) {
gf_mx_v(reader->mutex);
} else {
iso_sample = gf_isom_get_sample(reader->movie, track_number, sample_index, &di);
if (iso_sample) {
samples_processed++;
fprintf(stdout, "Found sample #%5d (#%5d) of length %8d, RAP: %d, DTS: "LLD", CTS: "LLD"\n", sample_index, samples_processed, iso_sample->dataLength, iso_sample->IsRAP, iso_sample->DTS, iso_sample->DTS+iso_sample->CTS_Offset);
sample_index++;
gf_isom_sample_del(&iso_sample);
if (sample_index > sample_count) {
u64 new_buffer_start;
u64 missing_bytes;
if (reader->state == EOS) {
reader->state = ERROR;
}
fprintf(stdout, "\nReleasing unnecessary buffers\n");
gf_isom_reset_tables(reader->movie, GF_TRUE);
#if 1
gf_isom_reset_data_offset(reader->movie, &new_buffer_start);
if (new_buffer_start) {
u32 offset = (u32)new_buffer_start;
memmove(reader->data, reader->data+offset, reader->data_size-offset);
reader->valid_data_size -= offset;
}
sprintf(reader->data_url, "gmem://%d@%p", reader->valid_data_size, reader->data);
gf_isom_refresh_fragmented(reader->movie, &missing_bytes, reader->data_url);
#endif
sample_count = new_sample_count - sample_count;
assert(sample_count == 0);
sample_index = 1;
}
} else {
GF_Err e = gf_isom_last_error(reader->movie);
fprintf(stdout, "Could not get sample %s\n", gf_error_to_string(e));
}
gf_mx_v(reader->mutex);
}
}
} else {
}
}
return 0;
}
int main(int argc, char **argv)
{
ISOProgressiveReader reader;
GF_Err e;
FILE *input;
u32 read_bytes;
u64 total_read_bytes;
u64 file_size;
u64 missing_bytes;
GF_Thread *reading_thread;
int ret = 0;
if (argc != 2) {
fprintf(stdout, "Usage: %s filename\n", argv[0]);
return 1;
}
#if defined(DEBUG) || defined(_DEBUG)
gf_sys_init(GF_MemTrackerSimple);
gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING);
gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO);
#else
gf_sys_init(GF_MemTrackerNone);
gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING);
#endif
input = gf_fopen(argv[1], "rb");
if (!input) {
fprintf(stdout, "Could not open file %s for reading.\n", argv[1]);
gf_sys_close();
return 1;
}
gf_fseek(input, 0, SEEK_END);
file_size = gf_ftell(input);
gf_fseek(input, 0, SEEK_SET);
memset(&reader, 0, sizeof(ISOProgressiveReader));
reading_thread = gf_th_new("ISO reading thread");
reader.mutex = gf_mx_new("ISO Segment");
reader.state = RUNNING;
reader.track_id = 1;
gf_th_run(reading_thread, iso_progressive_read_thread, &reader);
reader.data_size = BUFFER_BLOCK_SIZE;
reader.data = (u8 *)gf_malloc(reader.data_size);
reader.valid_data_size = 0;
total_read_bytes = 0;
while (1) {
gf_mx_p(reader.mutex);
if (reader.valid_data_size + BUFFER_BLOCK_SIZE > MAX_BUFFER_SIZE) {
fprintf(stdout, "Buffer full (%d/%d)- waiting to read next data \r", reader.valid_data_size, reader.data_size);
gf_mx_v(reader.mutex);
} else {
if (reader.valid_data_size + BUFFER_BLOCK_SIZE > reader.data_size) {
reader.data = (u8 *)gf_realloc(reader.data, reader.data_size + BUFFER_BLOCK_SIZE);
reader.data_size += BUFFER_BLOCK_SIZE;
}
read_bytes = fread(reader.data+reader.valid_data_size, 1, BUFFER_BLOCK_SIZE, input);
total_read_bytes += read_bytes;
fprintf(stdout, "Read "LLD" bytes of "LLD" bytes from input file %s (buffer status: %5d/%5d)\r", total_read_bytes, file_size, argv[1], reader.valid_data_size, reader.data_size);
if (read_bytes) {
reader.valid_data_size += read_bytes;
sprintf(reader.data_url, "gmem://%d@%p", reader.valid_data_size, reader.data);
} else {
gf_mx_v(reader.mutex);
break;
}
if (!reader.movie) {
e = gf_isom_open_progressive(reader.data_url, 0, 0, &reader.movie, &missing_bytes);
if (reader.movie) {
gf_isom_set_single_moof_mode(reader.movie, GF_TRUE);
}
gf_mx_v(reader.mutex);
if ((e == GF_OK || e == GF_ISOM_INCOMPLETE_FILE) && reader.movie) {
} else {
fprintf(stdout, "Error opening fragmented mp4 in progressive mode: %s (missing "LLD" bytes)\n", gf_error_to_string(e), missing_bytes);
ret = 1;
goto exit;
}
} else {
e = gf_isom_refresh_fragmented(reader.movie, &missing_bytes, reader.data_url);
gf_mx_v(reader.mutex);
if (e != GF_OK && e != GF_ISOM_INCOMPLETE_FILE) {
fprintf(stdout, "Error refreshing fragmented mp4: %s (missing "LLD" bytes)\n", gf_error_to_string(e), missing_bytes);
ret = 1;
goto exit;
}
}
}
}
exit:
reader.state = ret ? ERROR : EOS;
gf_th_stop(reading_thread);
gf_th_del(reading_thread);
gf_mx_del(reader.mutex);
gf_free(reader.data);
gf_isom_close(reader.movie);
gf_fclose(input);
gf_sys_close();
return ret;
}