Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
muxer: add experimental avlib/mp4 muxer
  • Loading branch information
perexg committed Jan 8, 2016
1 parent fe87cbf commit 61ad50a
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 4 deletions.
5 changes: 5 additions & 0 deletions src/muxer.c
Expand Up @@ -45,6 +45,7 @@ static struct strtab container_audio_mime[] = {
{ "audio/webm", MC_AVWEBM },
{ "audio/mp2t", MC_MPEGTS },
{ "audio/mpeg", MC_MPEGPS },
{ "audio/mp4", MC_AVMP4 },
{ "application/octet-stream", MC_PASS },
{ "application/octet-stream", MC_RAW },
};
Expand All @@ -61,6 +62,7 @@ static struct strtab container_video_mime[] = {
{ "video/webm", MC_AVWEBM },
{ "video/mp2t", MC_MPEGTS },
{ "video/mpeg", MC_MPEGPS },
{ "video/mp4", MC_AVMP4 },
{ "application/octet-stream", MC_PASS },
{ "application/octet-stream", MC_RAW },
};
Expand All @@ -79,6 +81,7 @@ static struct strtab container_name[] = {
{ "raw", MC_RAW },
{ "avmatroska", MC_AVMATROSKA },
{ "avwebm", MC_AVWEBM },
{ "avmp4", MC_AVMP4 },
};


Expand All @@ -95,6 +98,7 @@ static struct strtab container_audio_file_suffix[] = {
{ "bin", MC_RAW },
{ "mka", MC_AVMATROSKA },
{ "webm", MC_AVWEBM },
{ "mp4", MC_AVMP4 },
};


Expand All @@ -111,6 +115,7 @@ static struct strtab container_video_file_suffix[] = {
{ "bin", MC_RAW },
{ "mkv", MC_AVMATROSKA },
{ "webm", MC_AVWEBM },
{ "mp4", MC_AVMP4 },
};


Expand Down
1 change: 1 addition & 0 deletions src/muxer.h
Expand Up @@ -33,6 +33,7 @@ typedef enum {
MC_WEBM = 6,
MC_AVMATROSKA = 7,
MC_AVWEBM = 8,
MC_AVMP4 = 9,
} muxer_container_type_t;

typedef enum {
Expand Down
41 changes: 37 additions & 4 deletions src/muxer/muxer_libav.c
Expand Up @@ -91,6 +91,7 @@ lav_muxer_add_stream(lav_muxer_t *lm,
switch(lm->m_config.m_type) {
case MC_MATROSKA:
case MC_AVMATROSKA:
case MC_AVMP4:
st->time_base.num = 1000000;
st->time_base.den = 1;
break;
Expand Down Expand Up @@ -217,6 +218,18 @@ lav_muxer_support_stream(muxer_container_type_t mc,
ret |= (type == SCT_MPEG2AUDIO);
ret |= (type == SCT_AC3);

case MC_AVMP4:
ret |= (type == SCT_MPEG2VIDEO);
ret |= (type == SCT_H264);
ret |= (type == SCT_HEVC);

ret |= (type == SCT_MPEG2AUDIO);
ret |= (type == SCT_AC3);
ret |= (type == SCT_AAC);
ret |= (type == SCT_MP4A);
ret |= (type == SCT_EAC3);
break;

default:
break;
}
Expand Down Expand Up @@ -270,6 +283,7 @@ lav_muxer_init(muxer_t* m, struct streaming_start *ss, const char *name)
int i;
streaming_start_component_t *ssc;
AVFormatContext *oc;
AVDictionary *opts = NULL;
lav_muxer_t *lm = (lav_muxer_t*)m;
char app[128];

Expand Down Expand Up @@ -310,17 +324,25 @@ lav_muxer_init(muxer_t* m, struct streaming_start *ss, const char *name)
}
}

if(lm->m_config.m_type == MC_AVMP4) {
av_dict_set(&opts, "frag_duration", "1", 0);
av_dict_set(&opts, "ism_lookahead", "0", 0);
}

if(!lm->lm_oc->nb_streams) {
tvhlog(LOG_ERR, "libav", "No supported streams available");
lm->m_errors++;
return -1;
} else if(avformat_write_header(lm->lm_oc, NULL) < 0) {
} else if(avformat_write_header(lm->lm_oc, &opts) < 0) {
tvhlog(LOG_ERR, "libav", "Failed to write %s header",
muxer_container_type2txt(lm->m_config.m_type));
lm->m_errors++;
return -1;
}

if (opts)
av_dict_free(&opts);

lm->lm_init = 1;

return 0;
Expand Down Expand Up @@ -399,6 +421,7 @@ lav_muxer_write_pkt(muxer_t *m, streaming_message_type_t smt, void *data)
AVFormatContext *oc;
AVStream *st;
AVPacket packet;
enum AVCodecID codec_id;
th_pkt_t *pkt = (th_pkt_t*)data, *opkt;
lav_muxer_t *lm = (lav_muxer_t*)m;
unsigned char *tofree;
Expand Down Expand Up @@ -430,9 +453,10 @@ lav_muxer_write_pkt(muxer_t *m, streaming_message_type_t smt, void *data)

tofree = NULL;
av_init_packet(&packet);
codec_id = st->codec->codec_id;

if((lm->lm_h264_filter && st->codec->codec_id == AV_CODEC_ID_H264) ||
(lm->lm_hevc_filter && st->codec->codec_id == AV_CODEC_ID_HEVC)) {
if((lm->lm_h264_filter && codec_id == AV_CODEC_ID_H264) ||
(lm->lm_hevc_filter && codec_id == AV_CODEC_ID_HEVC)) {
pkt = avc_convert_pkt(opkt = pkt);
pkt_ref_dec(opkt);
if(av_bitstream_filter_filter(st->codec->codec_id == AV_CODEC_ID_H264 ?
Expand All @@ -451,15 +475,21 @@ lav_muxer_write_pkt(muxer_t *m, streaming_message_type_t smt, void *data)
} else {
tofree = packet.data;
}
} else if (st->codec->codec_id == AV_CODEC_ID_AAC) {
} else if (codec_id == AV_CODEC_ID_AAC) {
/* remove ADTS header */
packet.data = pktbuf_ptr(pkt->pkt_payload) + 7;
packet.size = pktbuf_len(pkt->pkt_payload) - 7;
} else {
if (lm->m_config.m_type == MC_AVMP4 &&
(codec_id == AV_CODEC_ID_H264 || codec_id == AV_CODEC_ID_HEVC)) {
pkt = avc_convert_pkt(opkt = pkt);
pkt_ref_dec(opkt);
}
packet.data = pktbuf_ptr(pkt->pkt_payload);
packet.size = pktbuf_len(pkt->pkt_payload);
}


packet.stream_index = st->index;

packet.pts = av_rescale_q(pkt->pkt_pts , mpeg_tc, st->time_base);
Expand Down Expand Up @@ -581,6 +611,9 @@ lav_muxer_create(const muxer_config_t *m_cfg)
case MC_AVWEBM:
mux_name = "webm";
break;
case MC_AVMP4:
mux_name = "mp4";
break;
default:
mux_name = muxer_container_type2txt(m_cfg->m_type);
break;
Expand Down
70 changes: 70 additions & 0 deletions src/profile.c
Expand Up @@ -1399,6 +1399,75 @@ profile_libav_matroska_builder(void)
return (profile_t *)pro;
}

/*
* LibAV/MP4 muxer
*/
typedef struct profile_libav_mp4 {
profile_t;
} profile_libav_mp4_t;

const idclass_t profile_libav_mp4_class =
{
.ic_super = &profile_class,
.ic_class = "profile-libav-mp4",
.ic_caption = N_("MP4/av-lib"),
};

static int
profile_libav_mp4_reopen(profile_chain_t *prch,
muxer_config_t *m_cfg, int flags)
{
muxer_config_t c;

if (m_cfg)
c = *m_cfg; /* do not alter the original parameter */
else
memset(&c, 0, sizeof(c));
if (c.m_type != MC_AVMP4)
c.m_type = MC_AVMP4;

assert(!prch->prch_muxer);
prch->prch_muxer = muxer_create(&c);
return 0;
}

static int
profile_libav_mp4_open(profile_chain_t *prch,
muxer_config_t *m_cfg, int flags, size_t qsize)
{
int r;

prch->prch_flags = SUBSCRIPTION_PACKET;
prch->prch_sq.sq_maxsize = qsize;

r = profile_htsp_work(prch, &prch->prch_sq.sq_st, 0, 0);
if (r) {
profile_chain_close(prch);
return r;
}

profile_libav_mp4_reopen(prch, m_cfg, flags);

return 0;
}

static muxer_container_type_t
profile_libav_mp4_get_mc(profile_t *_pro)
{
return MC_AVMP4;
}

static profile_t *
profile_libav_mp4_builder(void)
{
profile_libav_mp4_t *pro = calloc(1, sizeof(*pro));
pro->pro_sflags = SUBSCRIPTION_PACKET;
pro->pro_reopen = profile_libav_mp4_reopen;
pro->pro_open = profile_libav_mp4_open;
pro->pro_get_mc = profile_libav_mp4_get_mc;
return (profile_t *)pro;
}

/*
* Transcoding + packet-like muxers
*/
Expand Down Expand Up @@ -1916,6 +1985,7 @@ profile_init(void)
#if ENABLE_LIBAV
profile_register(&profile_libav_mpegts_class, profile_libav_mpegts_builder);
profile_register(&profile_libav_matroska_class, profile_libav_matroska_builder);
profile_register(&profile_libav_mp4_class, profile_libav_mp4_builder);
profile_transcode_experimental_codecs =
getenv("TVHEADEND_LIBAV_NO_EXPERIMENTAL_CODECS") ? 0 : 1;
profile_register(&profile_transcode_class, profile_transcode_builder);
Expand Down

0 comments on commit 61ad50a

Please sign in to comment.