Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
22a0827d
Commit
22a0827d
authored
Oct 26, 2012
by
Luca Barbato
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
hlsenc: stand alone hls segmenter
Simplifies usage but has higher latency.
parent
b9629acb
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
347 additions
and
1 deletion
+347
-1
muxers.texi
doc/muxers.texi
+21
-0
Makefile
libavformat/Makefile
+1
-0
allformats.c
libavformat/allformats.c
+1
-1
hlsenc.c
libavformat/hlsenc.c
+324
-0
No files found.
doc/muxers.texi
View file @
22a0827d
...
...
@@ -90,6 +90,27 @@ avconv -i INPUT -c:a pcm_u8 -c:v mpeg2video -f framecrc -
See also the @ref{crc} muxer.
@anchor{hls}
@section hls
Apple HTTP Live Streaming muxer that segments MPEG-TS according to
the HTTP Live Streaming specification.
It creates a playlist file and numbered segment files. The output
filename specifies the playlist filename; the segment filenames
receive the same basename as the playlist, a sequential number and
a .ts extension.
@example
avconv -i in.nut out.m3u8
@end example
@table @option
@item -hls_time segment length in seconds
@item -hls_list_size maximum number of playlist entries
@item -hls_wrap number after which index wraps
@end table
@anchor{image2}
@section image2
...
...
libavformat/Makefile
View file @
22a0827d
...
...
@@ -111,6 +111,7 @@ OBJS-$(CONFIG_H263_MUXER) += rawenc.o
OBJS-$(CONFIG_H264_DEMUXER)
+=
h264dec.o
rawdec.o
OBJS-$(CONFIG_H264_MUXER)
+=
rawenc.o
OBJS-$(CONFIG_HLS_DEMUXER)
+=
hls.o
OBJS-$(CONFIG_HLS_MUXER)
+=
hlsenc.o
mpegtsenc.o
OBJS-$(CONFIG_IDCIN_DEMUXER)
+=
idcin.o
OBJS-$(CONFIG_IFF_DEMUXER)
+=
iff.o
OBJS-$(CONFIG_ILBC_DEMUXER)
+=
ilbc.o
...
...
libavformat/allformats.c
View file @
22a0827d
...
...
@@ -106,7 +106,7 @@ void av_register_all(void)
REGISTER_MUXDEMUX
(
H261
,
h261
);
REGISTER_MUXDEMUX
(
H263
,
h263
);
REGISTER_MUXDEMUX
(
H264
,
h264
);
REGISTER_
DEMUXER
(
HLS
,
hls
);
REGISTER_
MUXDEMUX
(
HLS
,
hls
);
REGISTER_DEMUXER
(
IDCIN
,
idcin
);
REGISTER_DEMUXER
(
IFF
,
iff
);
REGISTER_MUXDEMUX
(
ILBC
,
ilbc
);
...
...
libavformat/hlsenc.c
0 → 100644
View file @
22a0827d
/*
* Apple HTTP Live Streaming segmenter
* Copyright (c) 2012, Luca Barbato
*
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Libav is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <float.h>
#include "libavutil/mathematics.h"
#include "libavutil/parseutils.h"
#include "libavutil/avstring.h"
#include "libavutil/opt.h"
#include "libavutil/log.h"
#include "avformat.h"
#include "internal.h"
typedef
struct
ListEntry
{
char
name
[
1024
];
int
duration
;
struct
ListEntry
*
next
;
}
ListEntry
;
typedef
struct
HLSContext
{
const
AVClass
*
class
;
// Class for private options.
int
number
;
AVOutputFormat
*
oformat
;
AVFormatContext
*
avf
;
float
time
;
// Set by a private option.
int
size
;
// Set by a private option.
int
wrap
;
// Set by a private option.
int64_t
recording_time
;
int
has_video
;
int64_t
start_pts
;
int64_t
end_pts
;
ListEntry
*
list
;
ListEntry
*
end_list
;
char
*
basename
;
AVIOContext
*
pb
;
}
HLSContext
;
static
int
hls_mux_init
(
AVFormatContext
*
s
)
{
HLSContext
*
hls
=
s
->
priv_data
;
AVFormatContext
*
oc
;
int
i
;
hls
->
avf
=
oc
=
avformat_alloc_context
();
if
(
!
oc
)
return
AVERROR
(
ENOMEM
);
oc
->
oformat
=
hls
->
oformat
;
oc
->
interrupt_callback
=
s
->
interrupt_callback
;
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
AVStream
*
st
;
if
(
!
(
st
=
avformat_new_stream
(
oc
,
NULL
)))
return
AVERROR
(
ENOMEM
);
avcodec_copy_context
(
st
->
codec
,
s
->
streams
[
i
]
->
codec
);
st
->
sample_aspect_ratio
=
s
->
streams
[
i
]
->
sample_aspect_ratio
;
}
return
0
;
}
static
int
append_entry
(
HLSContext
*
hls
,
uint64_t
duration
)
{
ListEntry
*
en
=
av_malloc
(
sizeof
(
*
en
));
if
(
!
en
)
return
AVERROR
(
ENOMEM
);
av_get_frame_filename
(
en
->
name
,
sizeof
(
en
->
name
),
hls
->
basename
,
hls
->
number
-
1
);
en
->
duration
=
duration
;
en
->
next
=
NULL
;
if
(
!
hls
->
list
)
hls
->
list
=
en
;
else
hls
->
end_list
->
next
=
en
;
hls
->
end_list
=
en
;
if
(
hls
->
number
>=
hls
->
size
)
{
en
=
hls
->
list
;
hls
->
list
=
en
->
next
;
av_free
(
en
);
}
return
0
;
}
static
void
free_entries
(
HLSContext
*
hls
)
{
ListEntry
*
p
=
hls
->
list
,
*
en
;
while
(
p
)
{
en
=
p
;
p
=
p
->
next
;
av_free
(
en
);
}
}
static
int
hls_window
(
AVFormatContext
*
s
,
int
last
)
{
HLSContext
*
hls
=
s
->
priv_data
;
ListEntry
*
en
;
int
ret
=
0
;
if
((
ret
=
avio_open2
(
&
hls
->
pb
,
s
->
filename
,
AVIO_FLAG_WRITE
,
&
s
->
interrupt_callback
,
NULL
))
<
0
)
goto
fail
;
avio_printf
(
hls
->
pb
,
"#EXTM3U
\n
"
);
avio_printf
(
hls
->
pb
,
"#EXT-X-VERSION:3
\n
"
);
avio_printf
(
hls
->
pb
,
"#EXT-X-TARGETDURATION:%d
\n
"
,
(
int
)
hls
->
time
);
avio_printf
(
hls
->
pb
,
"#EXT-X-MEDIA-SEQUENCE:%d
\n
"
,
FFMAX
(
0
,
hls
->
number
-
hls
->
size
));
for
(
en
=
hls
->
list
;
en
;
en
=
en
->
next
)
{
avio_printf
(
hls
->
pb
,
"#EXTINF:%d,
\n
"
,
en
->
duration
);
avio_printf
(
hls
->
pb
,
"%s
\n
"
,
en
->
name
);
}
if
(
last
)
avio_printf
(
hls
->
pb
,
"#EXT-X-ENDLIST
\n
"
);
fail:
avio_closep
(
&
hls
->
pb
);
return
ret
;
}
static
int
hls_start
(
AVFormatContext
*
s
)
{
HLSContext
*
c
=
s
->
priv_data
;
AVFormatContext
*
oc
=
c
->
avf
;
int
err
=
0
;
if
(
c
->
wrap
)
c
->
number
%=
c
->
wrap
;
if
(
av_get_frame_filename
(
oc
->
filename
,
sizeof
(
oc
->
filename
),
c
->
basename
,
c
->
number
++
)
<
0
)
return
AVERROR
(
EINVAL
);
if
((
err
=
avio_open2
(
&
oc
->
pb
,
oc
->
filename
,
AVIO_FLAG_WRITE
,
&
s
->
interrupt_callback
,
NULL
))
<
0
)
return
err
;
if
(
oc
->
oformat
->
priv_class
&&
oc
->
priv_data
)
av_opt_set
(
oc
->
priv_data
,
"mpegts_flags"
,
"resend_headers"
,
0
);
return
0
;
}
static
int
hls_write_header
(
AVFormatContext
*
s
)
{
HLSContext
*
hls
=
s
->
priv_data
;
int
ret
,
i
;
char
*
p
;
const
char
*
pattern
=
"%d.ts"
;
int
basename_size
=
strlen
(
s
->
filename
)
+
strlen
(
pattern
);
hls
->
number
=
0
;
hls
->
recording_time
=
hls
->
time
*
1000000
;
hls
->
start_pts
=
AV_NOPTS_VALUE
;
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
hls
->
has_video
+=
s
->
streams
[
i
]
->
codec
->
codec_type
==
AVMEDIA_TYPE_VIDEO
;
if
(
hls
->
has_video
>
1
)
av_log
(
s
,
AV_LOG_WARNING
,
"More than a single video stream present, "
"expect issues decoding it.
\n
"
);
hls
->
oformat
=
av_guess_format
(
"mpegts"
,
NULL
,
NULL
);
if
(
!
hls
->
oformat
)
{
ret
=
AVERROR_MUXER_NOT_FOUND
;
goto
fail
;
}
hls
->
basename
=
av_malloc
(
basename_size
);
if
(
!
hls
->
basename
)
{
ret
=
AVERROR
(
ENOMEM
);
goto
fail
;
}
strcpy
(
hls
->
basename
,
s
->
filename
);
p
=
strrchr
(
hls
->
basename
,
'.'
);
if
(
p
)
*
p
=
'\0'
;
av_strlcat
(
hls
->
basename
,
"%d.ts"
,
basename_size
);
if
((
ret
=
hls_mux_init
(
s
))
<
0
)
goto
fail
;
if
((
ret
=
hls_start
(
s
))
<
0
)
goto
fail
;
if
((
ret
=
avformat_write_header
(
hls
->
avf
,
NULL
))
<
0
)
return
ret
;
fail:
if
(
ret
)
{
av_free
(
hls
->
basename
);
if
(
hls
->
avf
)
avformat_free_context
(
hls
->
avf
);
}
return
ret
;
}
static
int
hls_write_packet
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
{
HLSContext
*
hls
=
s
->
priv_data
;
AVFormatContext
*
oc
=
hls
->
avf
;
AVStream
*
st
=
s
->
streams
[
pkt
->
stream_index
];
int64_t
end_pts
=
hls
->
recording_time
*
hls
->
number
;
int
ret
;
if
(
hls
->
start_pts
==
AV_NOPTS_VALUE
)
{
hls
->
start_pts
=
pkt
->
pts
;
hls
->
end_pts
=
pkt
->
pts
;
}
end_pts
+=
hls
->
start_pts
;
if
((
hls
->
has_video
&&
st
->
codec
->
codec_type
==
AVMEDIA_TYPE_VIDEO
)
&&
av_compare_ts
(
pkt
->
pts
,
st
->
time_base
,
end_pts
,
AV_TIME_BASE_Q
)
>=
0
&&
pkt
->
flags
&
AV_PKT_FLAG_KEY
)
{
append_entry
(
hls
,
av_rescale
(
pkt
->
pts
-
hls
->
end_pts
,
st
->
time_base
.
num
,
st
->
time_base
.
den
));
hls
->
end_pts
=
pkt
->
pts
;
av_write_frame
(
oc
,
NULL
);
/* Flush any buffered data */
avio_close
(
oc
->
pb
);
ret
=
hls_start
(
s
);
if
(
ret
)
return
ret
;
oc
=
hls
->
avf
;
if
((
ret
=
hls_window
(
s
,
0
))
<
0
)
return
ret
;
}
ret
=
ff_write_chained
(
oc
,
pkt
->
stream_index
,
pkt
,
s
);
return
ret
;
}
static
int
hls_write_trailer
(
struct
AVFormatContext
*
s
)
{
HLSContext
*
hls
=
s
->
priv_data
;
AVFormatContext
*
oc
=
hls
->
avf
;
av_write_trailer
(
oc
);
avio_closep
(
&
oc
->
pb
);
avformat_free_context
(
oc
);
av_free
(
hls
->
basename
);
hls_window
(
s
,
1
);
free_entries
(
hls
);
avio_close
(
hls
->
pb
);
return
0
;
}
#define OFFSET(x) offsetof(HLSContext, x)
#define E AV_OPT_FLAG_ENCODING_PARAM
static
const
AVOption
options
[]
=
{
{
"hls_time"
,
"segment length in seconds"
,
OFFSET
(
time
),
AV_OPT_TYPE_FLOAT
,
{.
dbl
=
2
},
0
,
FLT_MAX
,
E
},
{
"hls_list_size"
,
"maximum number of playlist entries"
,
OFFSET
(
size
),
AV_OPT_TYPE_INT
,
{.
i64
=
5
},
0
,
INT_MAX
,
E
},
{
"hls_wrap"
,
"number after which the index wraps"
,
OFFSET
(
wrap
),
AV_OPT_TYPE_INT
,
{.
i64
=
0
},
0
,
INT_MAX
,
E
},
{
NULL
},
};
static
const
AVClass
hls_class
=
{
.
class_name
=
"hls muxer"
,
.
item_name
=
av_default_item_name
,
.
option
=
options
,
.
version
=
LIBAVUTIL_VERSION_INT
,
};
AVOutputFormat
ff_hls_muxer
=
{
.
name
=
"hls"
,
.
long_name
=
NULL_IF_CONFIG_SMALL
(
"hls"
),
.
extensions
=
"m3u8"
,
.
priv_data_size
=
sizeof
(
HLSContext
),
.
audio_codec
=
AV_CODEC_ID_MP2
,
.
video_codec
=
AV_CODEC_ID_MPEG2VIDEO
,
.
flags
=
AVFMT_NOFILE
|
AVFMT_ALLOW_FLUSH
,
.
write_header
=
hls_write_header
,
.
write_packet
=
hls_write_packet
,
.
write_trailer
=
hls_write_trailer
,
.
priv_class
=
&
hls_class
,
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment