|  | @@ -48,6 +48,12 @@ | 
														
													
														
															
																|  |  | #include "vpcc.h" |  |  | #include "vpcc.h" | 
														
													
														
															
																|  |  | #include "dash.h" |  |  | #include "dash.h" | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | typedef enum { | 
														
													
														
															
																|  |  |  |  |  | SEGMENT_TYPE_MP4 = 0, | 
														
													
														
															
																|  |  |  |  |  | SEGMENT_TYPE_WEBM, | 
														
													
														
															
																|  |  |  |  |  | SEGMENT_TYPE_NB | 
														
													
														
															
																|  |  |  |  |  | } SegmentType; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  | typedef struct Segment { |  |  | typedef struct Segment { | 
														
													
														
															
																|  |  | char file[1024]; |  |  | char file[1024]; | 
														
													
														
															
																|  |  | int64_t start_pos; |  |  | int64_t start_pos; | 
														
													
												
													
														
															
																|  | @@ -69,7 +75,6 @@ typedef struct OutputStream { | 
														
													
														
															
																|  |  | AVFormatContext *ctx; |  |  | AVFormatContext *ctx; | 
														
													
														
															
																|  |  | int ctx_inited, as_idx; |  |  | int ctx_inited, as_idx; | 
														
													
														
															
																|  |  | AVIOContext *out; |  |  | AVIOContext *out; | 
														
													
														
															
																|  |  | char format_name[8]; |  |  |  | 
														
													
														
															
																|  |  | int packets_written; |  |  | int packets_written; | 
														
													
														
															
																|  |  | char initfile[1024]; |  |  | char initfile[1024]; | 
														
													
														
															
																|  |  | int64_t init_start_pos, pos; |  |  | int64_t init_start_pos, pos; | 
														
													
												
													
														
															
																|  | @@ -126,6 +131,8 @@ typedef struct DASHContext { | 
														
													
														
															
																|  |  | int64_t timeout; |  |  | int64_t timeout; | 
														
													
														
															
																|  |  | int index_correction; |  |  | int index_correction; | 
														
													
														
															
																|  |  | char *format_options_str; |  |  | char *format_options_str; | 
														
													
														
															
																|  |  |  |  |  | SegmentType segment_type; | 
														
													
														
															
																|  |  |  |  |  | const char *format_name; | 
														
													
														
															
																|  |  | } DASHContext; |  |  | } DASHContext; | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | static struct codec_string { |  |  | static struct codec_string { | 
														
													
												
													
														
															
																|  | @@ -139,6 +146,15 @@ static struct codec_string { | 
														
													
														
															
																|  |  | { 0, NULL } |  |  | { 0, NULL } | 
														
													
														
															
																|  |  | }; |  |  | }; | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | static struct format_string { | 
														
													
														
															
																|  |  |  |  |  | SegmentType segment_type; | 
														
													
														
															
																|  |  |  |  |  | const char *str; | 
														
													
														
															
																|  |  |  |  |  | } formats[] = { | 
														
													
														
															
																|  |  |  |  |  | { SEGMENT_TYPE_MP4, "mp4" }, | 
														
													
														
															
																|  |  |  |  |  | { SEGMENT_TYPE_WEBM, "webm" }, | 
														
													
														
															
																|  |  |  |  |  | { 0, NULL } | 
														
													
														
															
																|  |  |  |  |  | }; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  | static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, |  |  | static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, | 
														
													
														
															
																|  |  | AVDictionary **options) { |  |  | AVDictionary **options) { | 
														
													
														
															
																|  |  | DASHContext *c = s->priv_data; |  |  | DASHContext *c = s->priv_data; | 
														
													
												
													
														
															
																|  | @@ -172,6 +188,14 @@ static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filenam | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | static const char *get_format_str(SegmentType segment_type) { | 
														
													
														
															
																|  |  |  |  |  | int i; | 
														
													
														
															
																|  |  |  |  |  | for (i = 0; i < SEGMENT_TYPE_NB; i++) | 
														
													
														
															
																|  |  |  |  |  | if (formats[i].segment_type == segment_type) | 
														
													
														
															
																|  |  |  |  |  | return formats[i].str; | 
														
													
														
															
																|  |  |  |  |  | return NULL; | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  | static void set_vp9_codec_str(AVFormatContext *s, AVCodecParameters *par, |  |  | static void set_vp9_codec_str(AVFormatContext *s, AVCodecParameters *par, | 
														
													
														
															
																|  |  | AVRational *frame_rate, char *str, int size) { |  |  | AVRational *frame_rate, char *str, int size) { | 
														
													
														
															
																|  |  | VPCC vpcc; |  |  | VPCC vpcc; | 
														
													
												
													
														
															
																|  | @@ -582,13 +606,13 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind | 
														
													
														
															
																|  |  | if (as->media_type == AVMEDIA_TYPE_VIDEO) { |  |  | if (as->media_type == AVMEDIA_TYPE_VIDEO) { | 
														
													
														
															
																|  |  | AVStream *st = s->streams[i]; |  |  | AVStream *st = s->streams[i]; | 
														
													
														
															
																|  |  | avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"", |  |  | avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"", | 
														
													
														
															
																|  |  | i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | i, c->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height); | 
														
													
														
															
																|  |  | if (st->avg_frame_rate.num) |  |  | if (st->avg_frame_rate.num) | 
														
													
														
															
																|  |  | avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den); |  |  | avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den); | 
														
													
														
															
																|  |  | avio_printf(out, ">\n"); |  |  | avio_printf(out, ">\n"); | 
														
													
														
															
																|  |  | } else { |  |  | } else { | 
														
													
														
															
																|  |  | avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/%s\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n", |  |  | avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/%s\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n", | 
														
													
														
															
																|  |  | i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | i, c->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate); | 
														
													
														
															
																|  |  | avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n", |  |  | avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n", | 
														
													
														
															
																|  |  | s->streams[i]->codecpar->channels); |  |  | s->streams[i]->codecpar->channels); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
												
													
														
															
																|  | @@ -960,27 +984,10 @@ static int dash_init(AVFormatContext *s) | 
														
													
														
															
																|  |  | if (!ctx) |  |  | if (!ctx) | 
														
													
														
															
																|  |  | return AVERROR(ENOMEM); |  |  | return AVERROR(ENOMEM); | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | // choose muxer based on codec: webm for VP8 and opus, mp4 otherwise |  |  |  | 
														
													
														
															
																|  |  | // note: os->format_name is also used as part of the mimetype of the |  |  |  | 
														
													
														
															
																|  |  | //       representation, e.g. video/<format_name> |  |  |  | 
														
													
														
															
																|  |  | if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VP8 || |  |  |  | 
														
													
														
															
																|  |  | s->streams[i]->codecpar->codec_id == AV_CODEC_ID_OPUS || |  |  |  | 
														
													
														
															
																|  |  | s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VORBIS) { |  |  |  | 
														
													
														
															
																|  |  | snprintf(os->format_name, sizeof(os->format_name), "webm"); |  |  |  | 
														
													
														
															
																|  |  | 
 |  |  |  | 
														
													
														
															
																|  |  | if (s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { |  |  |  | 
														
													
														
															
																|  |  | av_log(s, AV_LOG_ERROR, |  |  |  | 
														
													
														
															
																|  |  | "WebM support in dashenc is experimental and has not " |  |  |  | 
														
													
														
															
																|  |  | "been validated. For testing purposes, make sure " |  |  |  | 
														
													
														
															
																|  |  | "to add -strict experimental and override " |  |  |  | 
														
													
														
															
																|  |  | "-init_seg_name and -media_seg_name to end with " |  |  |  | 
														
													
														
															
																|  |  | "the extension 'webm'.\n"); |  |  |  | 
														
													
														
															
																|  |  | return AVERROR(EINVAL); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | } else { |  |  |  | 
														
													
														
															
																|  |  | snprintf(os->format_name, sizeof(os->format_name), "mp4"); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | ctx->oformat = av_guess_format(os->format_name, NULL, NULL); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | c->format_name = get_format_str(c->segment_type); | 
														
													
														
															
																|  |  |  |  |  | if (!c->format_name) | 
														
													
														
															
																|  |  |  |  |  | return AVERROR_MUXER_NOT_FOUND; | 
														
													
														
															
																|  |  |  |  |  | ctx->oformat = av_guess_format(c->format_name, NULL, NULL); | 
														
													
														
															
																|  |  | if (!ctx->oformat) |  |  | if (!ctx->oformat) | 
														
													
														
															
																|  |  | return AVERROR_MUXER_NOT_FOUND; |  |  | return AVERROR_MUXER_NOT_FOUND; | 
														
													
														
															
																|  |  | os->ctx = ctx; |  |  | os->ctx = ctx; | 
														
													
												
													
														
															
																|  | @@ -1023,7 +1030,8 @@ static int dash_init(AVFormatContext *s) | 
														
													
														
															
																|  |  | if (ret < 0) |  |  | if (ret < 0) | 
														
													
														
															
																|  |  | return ret; |  |  | return ret; | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | if (!strcmp(os->format_name, "mp4")) { |  |  |  | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | if (c->segment_type == SEGMENT_TYPE_MP4) { | 
														
													
														
															
																|  |  | if (c->streaming) |  |  | if (c->streaming) | 
														
													
														
															
																|  |  | av_dict_set(&opts, "movflags", "frag_every_frame+dash+delay_moov", 0); |  |  | av_dict_set(&opts, "movflags", "frag_every_frame+dash+delay_moov", 0); | 
														
													
														
															
																|  |  | else |  |  | else | 
														
													
												
													
														
															
																|  | @@ -1088,7 +1096,7 @@ static int dash_write_header(AVFormatContext *s) | 
														
													
														
															
																|  |  | // Flush init segment |  |  | // Flush init segment | 
														
													
														
															
																|  |  | // Only for WebM segment, since for mp4 delay_moov is set and |  |  | // Only for WebM segment, since for mp4 delay_moov is set and | 
														
													
														
															
																|  |  | // the init segment is thus flushed after the first packets. |  |  | // the init segment is thus flushed after the first packets. | 
														
													
														
															
																|  |  | if (strcmp(os->format_name, "mp4") && |  |  |  | 
														
													
														
															
																|  |  |  |  |  | if (c->segment_type == SEGMENT_TYPE_WEBM && | 
														
													
														
															
																|  |  | (ret = flush_init_segment(s, os)) < 0) |  |  | (ret = flush_init_segment(s, os)) < 0) | 
														
													
														
															
																|  |  | return ret; |  |  | return ret; | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
												
													
														
															
																|  | @@ -1259,7 +1267,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | if (!c->single_file) { |  |  | if (!c->single_file) { | 
														
													
														
															
																|  |  | if (!strcmp(os->format_name, "mp4") && !os->written_len) |  |  |  | 
														
													
														
															
																|  |  |  |  |  | if (c->segment_type == SEGMENT_TYPE_MP4 && !os->written_len) | 
														
													
														
															
																|  |  | write_styp(os->ctx->pb); |  |  | write_styp(os->ctx->pb); | 
														
													
														
															
																|  |  | } else { |  |  | } else { | 
														
													
														
															
																|  |  | snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, os->initfile); |  |  | snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, os->initfile); | 
														
													
												
													
														
															
																|  | @@ -1449,7 +1457,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | //write out the data immediately in streaming mode |  |  | //write out the data immediately in streaming mode | 
														
													
														
															
																|  |  | if (c->streaming && !strcmp(os->format_name, "mp4")) { |  |  |  | 
														
													
														
															
																|  |  |  |  |  | if (c->streaming && c->segment_type == SEGMENT_TYPE_MP4) { | 
														
													
														
															
																|  |  | int len = 0; |  |  | int len = 0; | 
														
													
														
															
																|  |  | uint8_t *buf = NULL; |  |  | uint8_t *buf = NULL; | 
														
													
														
															
																|  |  | if (!os->written_len) |  |  | if (!os->written_len) | 
														
													
												
													
														
															
																|  | @@ -1545,6 +1553,9 @@ static const AVOption options[] = { | 
														
													
														
															
																|  |  | { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, |  |  | { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, | 
														
													
														
															
																|  |  | { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, |  |  | { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, | 
														
													
														
															
																|  |  | { "format_options","set list of options for the container format (mp4/webm) used for dash", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0, E}, |  |  | { "format_options","set list of options for the container format (mp4/webm) used for dash", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0, E}, | 
														
													
														
															
																|  |  |  |  |  | { "dash_segment_type", "set dash segment files type", OFFSET(segment_type), AV_OPT_TYPE_INT, {.i64 = SEGMENT_TYPE_MP4 }, 0, SEGMENT_TYPE_NB - 1, E, "segment_type"}, | 
														
													
														
															
																|  |  |  |  |  | { "mp4", "make segment file in ISOBMFF format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MP4 }, 0, UINT_MAX,   E, "segment_type"}, | 
														
													
														
															
																|  |  |  |  |  | { "webm", "make segment file in WebM format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_WEBM }, 0, UINT_MAX,   E, "segment_type"}, | 
														
													
														
															
																|  |  | { NULL }, |  |  | { NULL }, | 
														
													
														
															
																|  |  | }; |  |  | }; | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
												
													
														
															
																|  | 
 |