mirror of
https://github.com/arut/nginx-rtmp-module.git
synced 2025-08-06 15:00:18 +08:00
added AAC support to HLS
This commit is contained in:
7
README
7
README
@ -15,7 +15,7 @@ NGINX-based RTMP server
|
|||||||
(experimental; Linux only)
|
(experimental; Linux only)
|
||||||
|
|
||||||
* HLS (HTTP Live Streaming) support
|
* HLS (HTTP Live Streaming) support
|
||||||
(experimental; H264/MP3 only)
|
(experimental; H264/AAC/MP3)
|
||||||
|
|
||||||
* HTTP callbacks on publish/play/record
|
* HTTP callbacks on publish/play/record
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ rtmp {
|
|||||||
|
|
||||||
application small {
|
application small {
|
||||||
live on;
|
live on;
|
||||||
# Video with rediced resolution comes here from ffmpeg
|
# Video with reduced resolution comes here from ffmpeg
|
||||||
}
|
}
|
||||||
|
|
||||||
application mypush {
|
application mypush {
|
||||||
@ -180,9 +180,8 @@ rtmp {
|
|||||||
# for the fragments. The directory contents is served via HTTP (see
|
# for the fragments. The directory contents is served via HTTP (see
|
||||||
# http{} section in config)
|
# http{} section in config)
|
||||||
#
|
#
|
||||||
# Incoming stream must be in H264/MP3. For iPhones use baseline H264
|
# Incoming stream must be in H264/AAC/MP3. For iPhones use baseline H264
|
||||||
# profile (see ffmpeg example).
|
# profile (see ffmpeg example).
|
||||||
#
|
|
||||||
# This example creates RTMP stream from movie ready for HLS:
|
# This example creates RTMP stream from movie ready for HLS:
|
||||||
#
|
#
|
||||||
# ffmpeg -loglevel verbose -re -i movie.avi -vcodec libx264
|
# ffmpeg -loglevel verbose -re -i movie.avi -vcodec libx264
|
||||||
|
@ -206,6 +206,30 @@ ngx_rtmp_hls_get_audio_codec(ngx_int_t cid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
ngx_rtmp_hls_chain2buffer(u_char *buffer, size_t size, ngx_chain_t *in,
|
||||||
|
size_t skip)
|
||||||
|
{
|
||||||
|
ngx_buf_t out;
|
||||||
|
|
||||||
|
out.pos = buffer;
|
||||||
|
out.last = buffer + size - FF_INPUT_BUFFER_PADDING_SIZE;
|
||||||
|
|
||||||
|
for (; in; in = in->next) {
|
||||||
|
size = in->buf->last - in->buf->pos;
|
||||||
|
if (size < skip) {
|
||||||
|
skip -= size;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
out.pos = ngx_cpymem(out.pos, in->buf->pos + skip, ngx_min(
|
||||||
|
size - skip, (size_t)(out.last - out.pos)));
|
||||||
|
skip = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.pos - buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_rtmp_hls_init_video(ngx_rtmp_session_t *s)
|
ngx_rtmp_hls_init_video(ngx_rtmp_session_t *s)
|
||||||
{
|
{
|
||||||
@ -295,7 +319,7 @@ ngx_rtmp_hls_init_audio(ngx_rtmp_session_t *s)
|
|||||||
stream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
|
stream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||||
stream->codec->sample_fmt = (codec_ctx->sample_size == 1 ?
|
stream->codec->sample_fmt = (codec_ctx->sample_size == 1 ?
|
||||||
AV_SAMPLE_FMT_U8 : AV_SAMPLE_FMT_S16);
|
AV_SAMPLE_FMT_U8 : AV_SAMPLE_FMT_S16);
|
||||||
stream->codec->sample_rate = codec_ctx->sample_rate;
|
stream->codec->sample_rate = 48000;/*codec_ctx->sample_rate;*/
|
||||||
stream->codec->bit_rate = 128000;
|
stream->codec->bit_rate = 128000;
|
||||||
stream->codec->channels = codec_ctx->audio_channels;
|
stream->codec->channels = codec_ctx->audio_channels;
|
||||||
|
|
||||||
@ -419,8 +443,12 @@ static ngx_int_t
|
|||||||
ngx_rtmp_hls_open_file(ngx_rtmp_session_t *s, u_char *fpath)
|
ngx_rtmp_hls_open_file(ngx_rtmp_session_t *s, u_char *fpath)
|
||||||
{
|
{
|
||||||
ngx_rtmp_hls_ctx_t *ctx;
|
ngx_rtmp_hls_ctx_t *ctx;
|
||||||
|
ngx_rtmp_codec_ctx_t *codec_ctx;
|
||||||
|
AVStream *astream;
|
||||||
|
static u_char buffer[NGX_RTMP_HLS_BUFSIZE];
|
||||||
|
|
||||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module);
|
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module);
|
||||||
|
codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
|
||||||
if (ctx == NULL || ctx->out_format == NULL) {
|
if (ctx == NULL || ctx->out_format == NULL) {
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
@ -435,6 +463,21 @@ ngx_rtmp_hls_open_file(ngx_rtmp_session_t *s, u_char *fpath)
|
|||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
astream = NULL;
|
||||||
|
if (codec_ctx && codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC
|
||||||
|
&& codec_ctx->aac_header && codec_ctx->aac_header->buf->last -
|
||||||
|
codec_ctx->aac_header->buf->pos > 2
|
||||||
|
&& ctx->audio)
|
||||||
|
{
|
||||||
|
astream = ctx->out_format->streams[ctx->out_astream];
|
||||||
|
astream->codec->extradata = buffer;
|
||||||
|
astream->codec->extradata_size = ngx_rtmp_hls_chain2buffer(buffer,
|
||||||
|
sizeof(buffer), codec_ctx->aac_header, 2);
|
||||||
|
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||||
|
"hls: setting AAC extradata %i bytes",
|
||||||
|
(ngx_int_t)astream->codec->extradata_size);
|
||||||
|
}
|
||||||
|
|
||||||
/* write header */
|
/* write header */
|
||||||
if (avformat_write_header(ctx->out_format, NULL) < 0) {
|
if (avformat_write_header(ctx->out_format, NULL) < 0) {
|
||||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||||
@ -442,6 +485,11 @@ ngx_rtmp_hls_open_file(ngx_rtmp_session_t *s, u_char *fpath)
|
|||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (astream) {
|
||||||
|
astream->codec->extradata = NULL;
|
||||||
|
astream->codec->extradata_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->opened = 1;
|
ctx->opened = 1;
|
||||||
ctx->nal_bytes = -1;
|
ctx->nal_bytes = -1;
|
||||||
|
|
||||||
@ -802,13 +850,16 @@ ngx_rtmp_hls_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||||||
{
|
{
|
||||||
ngx_rtmp_hls_app_conf_t *hacf;
|
ngx_rtmp_hls_app_conf_t *hacf;
|
||||||
ngx_rtmp_hls_ctx_t *ctx;
|
ngx_rtmp_hls_ctx_t *ctx;
|
||||||
|
ngx_rtmp_codec_ctx_t *codec_ctx;
|
||||||
AVPacket packet;
|
AVPacket packet;
|
||||||
ngx_buf_t out;
|
|
||||||
static u_char buffer[NGX_RTMP_HLS_BUFSIZE];
|
static u_char buffer[NGX_RTMP_HLS_BUFSIZE];
|
||||||
|
|
||||||
hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module);
|
hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module);
|
||||||
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module);
|
ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module);
|
||||||
if (hacf == NULL || !hacf->hls || ctx == NULL || h->mlen < 1) {
|
codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);
|
||||||
|
if (hacf == NULL || !hacf->hls || ctx == NULL || codec_ctx == NULL ||
|
||||||
|
h->mlen < 1)
|
||||||
|
{
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -824,22 +875,26 @@ ngx_rtmp_hls_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
|
|||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy audio data */
|
|
||||||
out.pos = buffer;
|
|
||||||
out.last = buffer + sizeof(buffer) - FF_INPUT_BUFFER_PADDING_SIZE;
|
|
||||||
|
|
||||||
for (; in; in = in->next) {
|
|
||||||
out.pos = ngx_cpymem(out.pos, in->buf->pos, ngx_min(
|
|
||||||
in->buf->last - in->buf->pos, out.last - out.pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write to file */
|
/* write to file */
|
||||||
av_init_packet(&packet);
|
av_init_packet(&packet);
|
||||||
packet.dts = h->timestamp * 90;
|
packet.dts = h->timestamp * 90;
|
||||||
packet.pts = packet.dts;
|
packet.pts = packet.dts;
|
||||||
packet.stream_index = ctx->out_astream;
|
packet.stream_index = ctx->out_astream;
|
||||||
packet.data = buffer + 1;
|
packet.data = buffer;
|
||||||
packet.size = out.pos - buffer - 1;
|
packet.size = ngx_rtmp_hls_chain2buffer(buffer, sizeof(buffer), in, 1);
|
||||||
|
|
||||||
|
if (codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC) {
|
||||||
|
if (packet.size == 0) {
|
||||||
|
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||||
|
"hls: malformed AAC packet");
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
++packet.data;
|
||||||
|
--packet.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
|
||||||
|
"hls: audio buffer %uD", *(uint32_t*)packet.data);
|
||||||
|
|
||||||
if (av_interleaved_write_frame(ctx->out_format, &packet) < 0) {
|
if (av_interleaved_write_frame(ctx->out_format, &packet) < 0) {
|
||||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||||
|
Reference in New Issue
Block a user