static void *htsp_server, *htsp_server_2;
-#define HTSP_PROTO_VERSION 16
+#define HTSP_PROTO_VERSION 17
#define HTSP_ASYNC_OFF 0x00
#define HTSP_ASYNC_ON 0x01
int hs_first;
+ int hs_merge_meta_compomentidx;
+
} htsp_subscription_t;
[PKT_B_FRAME] = 'B',
};
+static th_pkt_t *merge_pkt(th_pkt_t *pkt, size_t payloadlen)
+{
+ th_pkt_t *n = pkt_alloc(NULL, 0, 0, 0);
+ *n = *pkt;
+ n->pkt_refcount = 1;
+ n->pkt_meta = NULL;
+ n->pkt_payload = pktbuf_alloc(NULL, payloadlen);
+ memcpy(pktbuf_ptr(n->pkt_payload),
+ pktbuf_ptr(pkt->pkt_meta), pktbuf_len(pkt->pkt_meta));
+ memcpy(pktbuf_ptr(n->pkt_payload) + pktbuf_len(pkt->pkt_meta),
+ pktbuf_ptr(pkt->pkt_payload), pktbuf_len(pkt->pkt_payload));
+ pkt_ref_dec(pkt);
+ return n;
+}
+
/**
* Build a htsmsg from a th_pkt and enqueue it on our HTSP service
*/
htsp_connection_t *htsp = hs->hs_htsp;
int64_t ts;
int qlen = hs->hs_q.hmq_payload;
+ size_t payloadlen;
if(!htsp_is_stream_enabled(hs, pkt->pkt_componentindex)) {
pkt_ref_dec(pkt);
uint32_t dur = hs->hs_90khz ? pkt->pkt_duration : ts_rescale(pkt->pkt_duration, 1000000);
htsmsg_add_u32(m, "duration", dur);
- pkt = pkt_merge_header(pkt);
-
+ if (pkt->pkt_meta &&
+ hs->hs_merge_meta_compomentidx == pkt->pkt_componentindex) {
+ payloadlen = pktbuf_len(pkt->pkt_meta) + pktbuf_len(pkt->pkt_payload);
+ pkt = merge_pkt(pkt, payloadlen);
+ /* do it only once */
+ hs->hs_merge_meta_compomentidx = -1;
+ } else {
+ payloadlen = pktbuf_len(pkt->pkt_payload);
+ }
/**
* Since we will serialize directly we use 'binptr' which is a binary
* object that just points to data, thus avoiding a copy.
*/
- htsmsg_add_binptr(m, "payload", pktbuf_ptr(pkt->pkt_payload),
- pktbuf_len(pkt->pkt_payload));
- htsp_send(htsp, m, pkt->pkt_payload, &hs->hs_q, pktbuf_len(pkt->pkt_payload));
- atomic_add(&hs->hs_s->ths_bytes_out, pktbuf_len(pkt->pkt_payload));
+ htsmsg_add_binptr(m, "payload", pktbuf_ptr(pkt->pkt_payload), payloadlen);
+ htsp_send(htsp, m, pkt->pkt_payload, &hs->hs_q, payloadlen);
+ atomic_add(&hs->hs_s->ths_bytes_out, payloadlen);
if(hs->hs_last_report != dispatch_clock) {
tvhdebug("htsp", "%s - subscription start", hs->hs_htsp->htsp_logname);
+ hs->hs_merge_meta_compomentidx = -1;
+
for(i = 0; i < ss->ss_num_components; i++) {
const streaming_start_component_t *ssc = &ss->ss_components[i];
- if (ssc->ssc_type == SCT_MPEG2VIDEO || ssc->ssc_type == SCT_H264) {
+ if (SCT_ISVIDEO(ssc->ssc_type)) {
if (ssc->ssc_width == 0 || ssc->ssc_height == 0) {
hs->hs_wait_for_video = 1;
return;
htsmsg_add_u32(c, "ancillary_id", ssc->ssc_ancillary_id);
}
- if(ssc->ssc_type == SCT_MPEG2VIDEO || ssc->ssc_type == SCT_H264) {
+ if(SCT_ISVIDEO(ssc->ssc_type)) {
if(ssc->ssc_width)
htsmsg_add_u32(c, "width", ssc->ssc_width);
if(ssc->ssc_height)
htsmsg_add_u32(c, "rate", ssc->ssc_sri);
}
+ if (ssc->ssc_gh)
+ htsmsg_add_binptr(m, "meta", pktbuf_ptr(ssc->ssc_gh),
+ pktbuf_len(ssc->ssc_gh));
+
htsmsg_add_msg(streams, NULL, c);
+
+ if (ssc->ssc_type == SCT_H264 && hs->hs_htsp->htsp_version < 17) {
+ if (hs->hs_merge_meta_compomentidx < 0)
+ hs->hs_merge_meta_compomentidx = ssc->ssc_index;
+ else
+ tvherror("htsp", "multiple H264 video streams?");
+ }
}
htsmsg_add_msg(m, "streams", streams);
av_init_packet(&packet);
- if(st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO)
- pkt = pkt_merge_header(pkt);
-
if(lm->lm_h264_filter && st->codec->codec_id == AV_CODEC_ID_H264) {
if(av_bitstream_filter_filter(lm->lm_h264_filter,
st->codec,
typedef struct mk_track {
int index;
int enabled;
- int merge;
int type;
int tracknum;
int disabled;
case SCT_MPEG2VIDEO:
tracktype = 1;
codec_id = "V_MPEG2";
- mkm->tracks[i].merge = 1;
break;
case SCT_H264:
if(mark)
mk_mux_insert_chapter(mkm);
- if(t->merge)
- pkt = pkt_merge_header(pkt);
-
mk_write_frame_i(mkm, t, pkt);
pkt_ref_dec(pkt);
static void
pkt_destroy(th_pkt_t *pkt)
{
- if(pkt->pkt_payload != NULL)
- pktbuf_ref_dec(pkt->pkt_payload);
+ pktbuf_ref_dec(pkt->pkt_payload);
+ pktbuf_ref_dec(pkt->pkt_meta);
- if(pkt->pkt_header != NULL)
- pktbuf_ref_dec(pkt->pkt_header);
free(pkt);
}
}
-/**
- *
- */
-th_pkt_t *
-pkt_merge_header(th_pkt_t *pkt)
-{
- th_pkt_t *n;
- size_t s;
-
- if(pkt->pkt_header == NULL)
- return pkt;
-
- n = malloc(sizeof(th_pkt_t));
- *n = *pkt;
-
- n->pkt_refcount = 1;
- n->pkt_header = NULL;
-
- s = pktbuf_len(pkt->pkt_payload) + pktbuf_len(pkt->pkt_header);
- n->pkt_payload = pktbuf_alloc(NULL, s);
-
- memcpy(pktbuf_ptr(n->pkt_payload),
- pktbuf_ptr(pkt->pkt_header),
- pktbuf_len(pkt->pkt_header));
-
- memcpy(pktbuf_ptr(n->pkt_payload) + pktbuf_len(pkt->pkt_header),
- pktbuf_ptr(pkt->pkt_payload),
- pktbuf_len(pkt->pkt_payload));
-
- pkt_ref_dec(pkt);
- return n;
-}
-
-
-
/**
*
*/
n->pkt_refcount = 1;
- if(n->pkt_header)
- pktbuf_ref_inc(n->pkt_header);
-
- if(n->pkt_payload)
- pktbuf_ref_inc(n->pkt_payload);
+ pktbuf_ref_inc(n->pkt_meta);
+ pktbuf_ref_inc(n->pkt_payload);
return n;
}
return pr;
}
+/*
+ *
+ */
-
-void
+void
pktbuf_ref_dec(pktbuf_t *pb)
{
- if((atomic_add(&pb->pb_refcount, -1)) == 1) {
- free(pb->pb_data);
- free(pb);
+ if (pb) {
+ if((atomic_add(&pb->pb_refcount, -1)) == 1) {
+ free(pb->pb_data);
+ free(pb);
+ }
}
}
-void
+pktbuf_t *
pktbuf_ref_inc(pktbuf_t *pb)
{
- atomic_add(&pb->pb_refcount, 1);
+ if (pb) {
+ atomic_add(&pb->pb_refcount, 1);
+ return pb;
+ }
+ return NULL;
}
pktbuf_t *
/*
- * Packet nanagement
+ * Packet management
* Copyright (C) 2008 Andreas Ă–man
*
* This program is free software: you can redistribute it and/or modify
#ifndef PACKET_H_
#define PACKET_H_
+/**
+ * Packet buffer
+ */
typedef struct pktbuf {
int pb_refcount;
size_t pb_size;
} pktbuf_t;
-
-
/**
* Packets
*/
uint16_t pkt_aspect_num;
uint16_t pkt_aspect_den;
+ pktbuf_t *pkt_meta;
pktbuf_t *pkt_payload;
- pktbuf_t *pkt_header;
} th_pkt_t;
th_pkt_t *pkt_alloc(const void *data, size_t datalen, int64_t pts, int64_t dts);
-th_pkt_t *pkt_merge_header(th_pkt_t *pkt);
-
th_pkt_t *pkt_copy_shallow(th_pkt_t *pkt);
th_pktref_t *pktref_create(th_pkt_t *pkt);
+/*
+ *
+ */
+
void pktbuf_ref_dec(pktbuf_t *pb);
-void pktbuf_ref_inc(pktbuf_t *pb);
+pktbuf_t *pktbuf_ref_inc(pktbuf_t *pb);
pktbuf_t *pktbuf_alloc(const void *data, size_t size);
pktbuf_t *pktbuf_make(void *data, size_t size);
-#define pktbuf_len(pb) ((pb)->pb_size)
-#define pktbuf_ptr(pb) ((pb)->pb_data)
+static inline size_t pktbuf_len(pktbuf_t *pb) { return pb->pb_size; }
+static inline uint8_t *pktbuf_ptr(pktbuf_t *pb) { return pb->pb_data; }
#endif /* PACKET_H_ */
th_pkt_t *pkt = malloc(sizeof(th_pkt_t));
*pkt = *src;
pkt->pkt_refcount = 1;
- pkt->pkt_header = NULL;
+ pkt->pkt_meta = NULL;
pkt->pkt_payload = NULL;
- if (src->pkt_header) {
+ if (src->pkt_meta) {
sbuf_t headers;
sbuf_init(&headers);
- isom_write_avcc(&headers, pktbuf_ptr(src->pkt_header),
- pktbuf_len(src->pkt_header));
- pkt->pkt_header = pktbuf_make(headers.sb_data, headers.sb_ptr);
+ isom_write_avcc(&headers, pktbuf_ptr(src->pkt_meta),
+ pktbuf_len(src->pkt_meta));
+ pkt->pkt_meta = pktbuf_make(headers.sb_data, headers.sb_ptr);
}
sbuf_t payload;
sbuf_init(&payload);
- if(src->pkt_header)
- avc_parse_nal_units(&payload, pktbuf_ptr(src->pkt_header),
- pktbuf_len(src->pkt_header));
+ if(src->pkt_meta)
+ avc_parse_nal_units(&payload, pktbuf_ptr(src->pkt_meta),
+ pktbuf_len(src->pkt_meta));
avc_parse_nal_units(&payload, pktbuf_ptr(src->pkt_payload),
pktbuf_len(src->pkt_payload));
if(next_startcode == 0x100 || next_startcode > 0x1af) {
/* Last picture slice (because next not a slice) */
th_pkt_t *pkt = st->es_curpkt;
+ size_t metalen = 0;
if(pkt == NULL) {
/* no packet, may've been discarded by sanity checks here */
return 1;
}
if(st->es_global_data) {
- pkt->pkt_header = pktbuf_make(st->es_global_data,
- st->es_global_data_len);
+ pkt->pkt_meta = pktbuf_make(st->es_global_data,
+ metalen = st->es_global_data_len);
st->es_global_data = NULL;
st->es_global_data_len = 0;
}
- pkt->pkt_payload = pktbuf_make(st->es_buf.sb_data,
- st->es_buf.sb_ptr - 4);
+ if (metalen) {
+ pkt->pkt_payload = pktbuf_alloc(NULL, metalen + st->es_buf.sb_ptr - 4);
+ memcpy(pktbuf_ptr(pkt->pkt_payload), pktbuf_ptr(pkt->pkt_meta), metalen);
+ memcpy(pktbuf_ptr(pkt->pkt_payload) + metalen, st->es_buf.sb_data, st->es_buf.sb_ptr - 4);
+ sbuf_reset(&st->es_buf, 16000);
+ } else {
+ pkt->pkt_payload = pktbuf_make(st->es_buf.sb_data,
+ st->es_buf.sb_ptr - 4);
+ sbuf_steal_data(&st->es_buf);
+ }
pkt->pkt_duration = st->es_frame_duration;
- sbuf_steal_data(&st->es_buf);
parser_deliver(t, st, pkt, st->es_buf.sb_err);
st->es_curpkt = NULL;
if(pkt != NULL) {
if(st->es_global_data) {
- pkt->pkt_header = pktbuf_make(st->es_global_data,
- st->es_global_data_len);
+ pkt->pkt_meta = pktbuf_make(st->es_global_data,
+ st->es_global_data_len);
st->es_global_data = NULL;
st->es_global_data_len = 0;
}
t->s_current_pts = pkt->pkt_pts;
tvhtrace("parser",
- "pkt stream %2d %-12s type %c dts %10"PRId64" pts %10"PRId64
+ "pkt stream %2d %-12s type %c"
+ " dts %10"PRId64" (%10"PRId64") pts %10"PRId64" (%10"PRId64")"
" dur %10d len %10zu",
st->es_index,
streaming_component_type2txt(st->es_type),
pkt_frametype_to_char(pkt->pkt_frametype),
-#if 1
ts_rescale(pkt->pkt_pts, 1000000),
- ts_rescale(pkt->pkt_dts, 1000000),
-#else
pkt->pkt_dts,
+ ts_rescale(pkt->pkt_dts, 1000000),
pkt->pkt_pts,
-#endif
pkt->pkt_duration,
pktbuf_len(pkt->pkt_payload));
if(ssc->ssc_gh != NULL)
return;
- if(pkt->pkt_header != NULL) {
- ssc->ssc_gh = pkt->pkt_header;
+ if(pkt->pkt_meta != NULL) {
+ ssc->ssc_gh = pkt->pkt_meta;
pktbuf_ref_inc(ssc->ssc_gh);
return;
}
as->aud_dec_pts += (pkt->pkt_pts - as->aud_dec_pts);
}
- pkt = pkt_merge_header(pkt);
-
av_init_packet(&packet);
packet.data = pktbuf_ptr(pkt->pkt_payload);
packet.size = pktbuf_len(pkt->pkt_payload);
create_adts_header(pkt->pkt_payload, n->pkt_sri, octx->channels);
if (octx->extradata_size)
- n->pkt_header = pktbuf_alloc(octx->extradata, octx->extradata_size);
+ n->pkt_meta = pktbuf_alloc(octx->extradata, octx->extradata_size);
tvhtrace("transcode", "%04X: deliver audio (pts = %" PRIi64 ", delay = %i)",
shortid(t), n->pkt_pts, octx->delay);
}
}
- n->pkt_header = pktbuf_alloc(data, header_size);
+ n->pkt_meta = pktbuf_alloc(data, header_size);
}
}
}
if (octx->extradata_size)
- n->pkt_header = pktbuf_alloc(octx->extradata, octx->extradata_size);
+ n->pkt_meta = pktbuf_alloc(octx->extradata, octx->extradata_size);
else {
if (octx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
extract_mpeg2_global_data(n, epkt->data, epkt->size);
}
}
- pkt = pkt_merge_header(pkt);
-
av_init_packet(&packet);
packet.data = pktbuf_ptr(pkt->pkt_payload);
packet.size = pktbuf_len(pkt->pkt_payload);
}
if (type == SMT_PACKET) {
th_pkt_t *pkt = data;
- pkt->pkt_payload = pkt->pkt_header = NULL;
+ pkt->pkt_payload = pkt->pkt_meta = NULL;
pkt->pkt_refcount = 0;
*sm = streaming_msg_create_pkt(pkt);
- r = _read_pktbuf(fd, &pkt->pkt_header);
+ r = _read_pktbuf(fd, &pkt->pkt_meta);
if (r < 0) {
streaming_msg_free(*sm);
return r;
ssize_t ret = 0, err;
ret = err = _write_msg(fd, SMT_PACKET, time, pkt, sizeof(th_pkt_t));
if (err <= 0) return err;
- err = _write_pktbuf(fd, pkt->pkt_header);
+ err = _write_pktbuf(fd, pkt->pkt_meta);
if (err <= 0) return err;
ret += err;
err = _write_pktbuf(fd, pkt->pkt_payload);