added AAC support to HLS

This commit is contained in:
Roman Arutyunyan
2012-06-22 12:26:56 +04:00
parent 78f6ccd604
commit f48bcc5235
2 changed files with 77 additions and 23 deletions

7
README
View File

@ -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

View File

@ -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,