Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 75 additions & 38 deletions src/hls.c
Original file line number Diff line number Diff line change
Expand Up @@ -1467,7 +1467,7 @@ static int vod_download_segment(void **psession, hls_media_playlist_t *me, struc
int retries = 0;
int ret = 0;
while (true) {
MSG_PRINT("Downloading part %d\n", ms->sequence_number);
MSG_PRINT("Downloading part %d from %s\n", ms->sequence_number, ms->url);

memset(seg, 0x00, sizeof(*seg));
size_t size = 0;
Expand Down Expand Up @@ -1551,7 +1551,7 @@ uint8_t * find_first_ts_packet(ByteBuffer_t *buf) {
return NULL;
}

int download_hls(write_ctx_t *out_ctx, hls_media_playlist_t *me, hls_media_playlist_t *me_audio)
int download_hls(hls_media_playlist_t *me, hls_media_playlist_t *me_audio, bool merge, bool ignore_http_errors)
{
MSG_VERBOSE("Downloading segments.\n");
MSG_API("{\"d_t\":\"vod\"}\n"); // d_t - download type
Expand All @@ -1562,12 +1562,29 @@ int download_hls(write_ctx_t *out_ctx, hls_media_playlist_t *me, hls_media_playl
set_timeout_session(session, 2L, 3L);
assert(session);
time_t repTime = 0;
int i = 0;

uint64_t downloaded_duration_ms = 0;
int64_t download_size = 0;
struct ByteBuffer seg;
struct ByteBuffer seg_audio;

char prefix[5];
if (!merge) {
sprintf(prefix, "%03d_", i);
} else {
strcpy(prefix, "");
}

FILE *out_file = get_output_file(prefix);
if (!out_file) {
MSG_ERROR("Failed to open output file!\n");
return -1;
}

write_ctx_t out_ctx_ = {priv_write, out_file};
write_ctx_t *out_ctx = &out_ctx_;

struct hls_media_segment *ms = me->first_media_segment;
struct hls_media_segment *ms_audio = NULL;
merge_context_t merge_context;
Expand All @@ -1579,55 +1596,75 @@ int download_hls(write_ctx_t *out_ctx, hls_media_playlist_t *me, hls_media_playl
}

while(ms) {
if (0 != vod_download_segment(&session, me, ms, &seg)) {
break;
}

uint8_t *first_video_packet = find_first_ts_packet(&seg);
uint8_t *first_audio_packet = NULL;
if (ms_audio) {
if ( 0 != vod_download_segment(&session, me_audio, ms_audio, &seg_audio)) {
break;
if (0 == vod_download_segment(&session, me, ms, &seg)) {
uint8_t *first_video_packet = find_first_ts_packet(&seg);
uint8_t *first_audio_packet = NULL;
if (ms_audio) {
if ( 0 != vod_download_segment(&session, me_audio, ms_audio, &seg_audio)) {
break;
}
first_audio_packet = find_first_ts_packet(&seg_audio);
}
first_audio_packet = find_first_ts_packet(&seg_audio);
}

// first segment should be TS for success merge
if (first_video_packet && first_audio_packet) {
size_t video_len = seg.len - (first_video_packet - seg.data);
size_t audio_len = seg_audio.len - (first_audio_packet - seg_audio.data);

download_size += merge_packets(
&merge_context,
first_video_packet,
video_len,
first_audio_packet,
audio_len
);
} else {
download_size += out_ctx->write(seg.data, seg.len, out_ctx->opaque);
}
// first segment should be TS for success merge
if (first_video_packet && first_audio_packet) {
size_t video_len = seg.len - (first_video_packet - seg.data);
size_t audio_len = seg_audio.len - (first_audio_packet - seg_audio.data);

download_size += merge_packets(
&merge_context,
first_video_packet,
video_len,
first_audio_packet,
audio_len
);
} else {
download_size += out_ctx->write(seg.data, seg.len, out_ctx->opaque);
}

if (ms_audio) {
free(seg_audio.data);
ms_audio = ms_audio->next;
}
if (ms_audio) {
free(seg_audio.data);
ms_audio = ms_audio->next;
}

free(seg.data);
free(seg.data);

downloaded_duration_ms += ms->duration_ms;
downloaded_duration_ms += ms->duration_ms;

time_t curRepTime = time(NULL);
if ((curRepTime - repTime) >= 1) {
MSG_API("{\"t_d\":%u,\"d_d\":%u,\"d_s\":%"PRId64"}\n", (uint32_t)(me->total_duration_ms / 1000), (uint32_t)(downloaded_duration_ms / 1000), download_size);
repTime = curRepTime;
time_t curRepTime = time(NULL);
if ((curRepTime - repTime) >= 1) {
MSG_API("{\"t_d\":%u,\"d_d\":%u,\"d_s\":%"PRId64"}\n", (uint32_t)(me->total_duration_ms / 1000), (uint32_t)(downloaded_duration_ms / 1000), download_size);
repTime = curRepTime;
}
} else if (ignore_http_errors) {
MSG_WARNING("Ignoring error downloading segment %d\n", i+1);
} else {
break;
}

ms = ms->next;
i++;

if (ms && !merge) {
if (out_file) {
fclose(out_file);
}

sprintf(prefix, "%03d_", i);
out_file = get_output_file(prefix);
if (!out_file) {
MSG_ERROR("Failed to open output file!\n");
return -1;
}
}
}

MSG_API("{\"t_d\":%u,\"d_d\":%u,\"d_s\":%"PRId64"}\n", (uint32_t)(me->total_duration_ms / 1000), (uint32_t)(downloaded_duration_ms / 1000), download_size);

if (out_file) {
fclose(out_file);
}

if (session) {
clean_http_session(session);
}
Expand Down
2 changes: 1 addition & 1 deletion src/hls.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ int handle_hls_media_playlist(hls_media_playlist_t *me);
int download_live_hls(write_ctx_t *ctx, hls_media_playlist_t *me);
bool consecutive_sync_byte(uint8_t *buf, size_t len, uint8_t n);
uint8_t * find_first_ts_packet(ByteBuffer_t *buf);
int download_hls(write_ctx_t *ctx, hls_media_playlist_t *me, hls_media_playlist_t *me_audio);
int download_hls(hls_media_playlist_t *me, hls_media_playlist_t *me_audio, bool merge, bool ignore_http_errors);
int print_enc_keys(hls_media_playlist_t *me);
void print_hls_master_playlist(struct hls_master_playlist *ma);
void media_playlist_cleanup(hls_media_playlist_t *me);
Expand Down
92 changes: 11 additions & 81 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,80 +21,6 @@
#include "msg.h"
#include "misc.h"

static size_t priv_write(const uint8_t *data, size_t len, void *opaque) {
return fwrite(data, 1, len, opaque);
}

static bool is_file_exists(const char *filename)
{
#ifndef _MSC_VER
return access(filename, F_OK) != -1;
#else
struct stat info;
int ret = -1;

ret = stat(filename, &info);
return 0 == ret;
#endif
}

static FILE* get_output_file(void)
{
FILE *pFile = NULL;

if (hls_args.filename && 0 == strncmp(hls_args.filename, "-", 2)) {
// Set "stdout" to have binary mode:
fflush(stdout);
#if !defined(_MSC_VER) && !defined(__MINGW32__)
pFile = freopen(NULL, "wb", stdout);
#else
if (-1 != setmode(_fileno(stdout), _O_BINARY)) {
pFile = stdout;
}
#endif
fflush(stdout);
} else {
char filename[MAX_FILENAME_LEN];
if (hls_args.filename) {
strcpy(filename, hls_args.filename);
}
else {
strcpy(filename, "000_hls_output.ts");
}

if (is_file_exists(filename)) {
if (hls_args.force_overwrite) {
if (remove(filename) != 0) {
MSG_ERROR("Error overwriting file");
exit(1);
}
}
else {
char userchoice = '\0';
MSG_PRINT("File already exists. Overwrite? (y/n) ");
if (scanf("\n%c", &userchoice) && userchoice == 'y') {
if (remove(filename) != 0) {
MSG_ERROR("Error overwriting file");
exit(1);
}
}
else {
MSG_WARNING("Choose a different filename. Exiting.\n");
exit(0);
}
}
}

pFile = fopen(filename, "wb");
}

if (pFile == NULL)
{
MSG_ERROR("Error can not open output file\n");
exit(1);
}
return pFile;
}

static bool get_data_with_retry(char *url, char **hlsfile_source, char **finall_url, int tries)
{
Expand Down Expand Up @@ -389,16 +315,20 @@ int main(int argc, char *argv[])
}
} else {
int ret = -1;
FILE *out_file = get_output_file();
if (out_file) {
write_ctx_t out_ctx = {priv_write, out_file};
if (media_playlist.is_endlist) {
ret = download_hls(&out_ctx, &media_playlist, &audio_media_playlist);
} else {

if (media_playlist.is_endlist) {
ret = download_hls(&media_playlist, &audio_media_playlist, !hls_args.skip_merge,
hls_args.ignore_http_errors);
} else {
char prefix[] = "";
FILE *out_file = get_output_file(prefix);
if (out_file) {
write_ctx_t out_ctx = {priv_write, out_file};
ret = download_live_hls(&out_ctx, &media_playlist);
fclose(out_file);
}
fclose(out_file);
}

return ret ? 1 : 0;
}

Expand Down
Loading