mirror of https://git.ffmpeg.org/ffmpeg.git
avformat/webmdashenc: Avoid allocations, fix memleak
When using the WebM DASH Manifest muxer, every stream of each adaptation set has to contain a metadata entry containing the filename of the source file. In case of live stream manifests, said filename has to conform to a pattern of <file_description>_<representation_id>.<extension>. These pieces are used to create the other strings that are actually output. Up until now, these other strings would be allocated, used once and then freed directly after usage. This commit changes this: The function that allocated and assembled these strings now returns pointers to the '_' and '.' delimiters and so that the caller can easily pick substrings from it without needing to copy the string. Avoiding allocations also fixes a memleak: One of the allocated strings would leak upon a subsequent allocation failure. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
This commit is contained in:
parent
c1fab8637e
commit
f163b2eb27
|
@ -260,65 +260,24 @@ static void free_adaptation_sets(AVFormatContext *s) {
|
|||
}
|
||||
|
||||
/*
|
||||
* Parses a live header filename and computes the representation id,
|
||||
* initialization pattern and the media pattern. Pass NULL if you don't want to
|
||||
* compute any of those 3. Returns 0 on success and non-zero on failure.
|
||||
* Parses a live header filename and returns the position of the '_' and '.'
|
||||
* delimiting <file_description> and <representation_id>.
|
||||
*
|
||||
* Name of the header file should conform to the following pattern:
|
||||
* <file_description>_<representation_id>.hdr where <file_description> can be
|
||||
* anything. The chunks should be named according to the following pattern:
|
||||
* <file_description>_<representation_id>_<chunk_number>.chk
|
||||
*/
|
||||
static int parse_filename(char *filename, char **representation_id,
|
||||
char **initialization_pattern, char **media_pattern) {
|
||||
char *underscore_pos = NULL;
|
||||
char *period_pos = NULL;
|
||||
char *filename_str = av_strdup(filename);
|
||||
int ret = 0;
|
||||
|
||||
if (!filename_str) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
underscore_pos = strrchr(filename_str, '_');
|
||||
if (!underscore_pos) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto end;
|
||||
}
|
||||
period_pos = strchr(++underscore_pos, '.');
|
||||
if (!period_pos) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto end;
|
||||
}
|
||||
*(underscore_pos - 1) = 0;
|
||||
if (representation_id) {
|
||||
*representation_id = av_malloc(period_pos - underscore_pos + 1);
|
||||
if (!(*representation_id)) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
av_strlcpy(*representation_id, underscore_pos, period_pos - underscore_pos + 1);
|
||||
}
|
||||
if (initialization_pattern) {
|
||||
*initialization_pattern = av_asprintf("%s_$RepresentationID$.hdr",
|
||||
filename_str);
|
||||
if (!(*initialization_pattern)) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if (media_pattern) {
|
||||
*media_pattern = av_asprintf("%s_$RepresentationID$_$Number$.chk",
|
||||
filename_str);
|
||||
if (!(*media_pattern)) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
av_freep(&filename_str);
|
||||
return ret;
|
||||
static int split_filename(char *filename, char **underscore_pos,
|
||||
char **period_pos)
|
||||
{
|
||||
*underscore_pos = strrchr(filename, '_');
|
||||
if (!*underscore_pos)
|
||||
return AVERROR(EINVAL);
|
||||
*period_pos = strchr(*underscore_pos, '.');
|
||||
if (!*period_pos)
|
||||
return AVERROR(EINVAL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -377,46 +336,49 @@ static int write_adaptation_set(AVFormatContext *s, int as_index)
|
|||
if (w->is_live) {
|
||||
AVDictionaryEntry *filename =
|
||||
av_dict_get(s->streams[as->streams[0]]->metadata, FILENAME, NULL, 0);
|
||||
char *initialization_pattern = NULL;
|
||||
char *media_pattern = NULL;
|
||||
char *underscore_pos, *period_pos;
|
||||
int ret;
|
||||
if (!filename)
|
||||
return AVERROR(EINVAL);
|
||||
ret = parse_filename(filename->value, NULL, &initialization_pattern,
|
||||
&media_pattern);
|
||||
ret = split_filename(filename->value, &underscore_pos, &period_pos);
|
||||
if (ret) return ret;
|
||||
*underscore_pos = '\0';
|
||||
avio_printf(s->pb, "<ContentComponent id=\"1\" type=\"%s\"/>\n",
|
||||
par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
|
||||
avio_printf(s->pb, "<SegmentTemplate");
|
||||
avio_printf(s->pb, " timescale=\"1000\"");
|
||||
avio_printf(s->pb, " duration=\"%d\"", w->chunk_duration);
|
||||
avio_printf(s->pb, " media=\"%s\"", media_pattern);
|
||||
avio_printf(s->pb, " media=\"%s_$RepresentationID$_$Number$.chk\"",
|
||||
filename->value);
|
||||
avio_printf(s->pb, " startNumber=\"%d\"", w->chunk_start_index);
|
||||
avio_printf(s->pb, " initialization=\"%s\"", initialization_pattern);
|
||||
avio_printf(s->pb, " initialization=\"%s_$RepresentationID$.hdr\"",
|
||||
filename->value);
|
||||
avio_printf(s->pb, "/>\n");
|
||||
av_free(initialization_pattern);
|
||||
av_free(media_pattern);
|
||||
*underscore_pos = '_';
|
||||
}
|
||||
|
||||
for (i = 0; i < as->nb_streams; i++) {
|
||||
char *representation_id = NULL;
|
||||
char buf[25], *representation_id = buf, *underscore_pos, *period_pos;
|
||||
int ret;
|
||||
if (w->is_live) {
|
||||
AVDictionaryEntry *filename =
|
||||
av_dict_get(s->streams[as->streams[i]]->metadata, FILENAME, NULL, 0);
|
||||
if (!filename)
|
||||
return AVERROR(EINVAL);
|
||||
if (ret = parse_filename(filename->value, &representation_id, NULL, NULL))
|
||||
ret = split_filename(filename->value, &underscore_pos, &period_pos);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
representation_id = underscore_pos + 1;
|
||||
*period_pos = '\0';
|
||||
} else {
|
||||
representation_id = av_asprintf("%d", w->representation_id++);
|
||||
if (!representation_id) return AVERROR(ENOMEM);
|
||||
snprintf(buf, sizeof(buf), "%d", w->representation_id++);
|
||||
}
|
||||
ret = write_representation(s, s->streams[as->streams[i]],
|
||||
representation_id, !width_in_as,
|
||||
!height_in_as, !sample_rate_in_as);
|
||||
av_free(representation_id);
|
||||
if (ret) return ret;
|
||||
if (w->is_live)
|
||||
*period_pos = '.';
|
||||
}
|
||||
avio_printf(s->pb, "</AdaptationSet>\n");
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue