th_pkt_t * avc_convert_pkt(th_pkt_t *src) { th_pkt_t *pkt = malloc(sizeof(th_pkt_t)); *pkt = *src; pkt->pkt_refcount = 1; pkt->pkt_header = NULL; pkt->pkt_payload = NULL; if (src->pkt_header) { 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); } 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)); avc_parse_nal_units(&payload, pktbuf_ptr(src->pkt_payload), pktbuf_len(src->pkt_payload)); pkt->pkt_payload = pktbuf_make(payload.sb_data, payload.sb_ptr); pkt_ref_dec(src); return pkt; }
static ssize_t _read_pktbuf ( timeshift_file_t *tsf, int fd, pktbuf_t **pktbuf ) { ssize_t r, cnt = 0; size_t sz; /* Size */ r = _read_buf(tsf, fd, &sz, sizeof(sz)); if (r < 0) return -1; if (r != sizeof(sz)) return 0; cnt += r; /* Empty And Sanity Check */ if (!sz || sz > 1024 * 1024) { *pktbuf = NULL; return cnt; } /* Data */ *pktbuf = pktbuf_alloc(NULL, sz); r = _read_buf(tsf, fd, pktbuf_ptr(*pktbuf), sz); if (r != sz) { pktbuf_destroy(*pktbuf); *pktbuf = NULL; return r < 0 ? -1 : 0; } cnt += r; return cnt; }
/* * Write packet buffer */ static int _write_pktbuf ( timeshift_file_t *tsf, pktbuf_t *pktbuf ) { ssize_t ret, err; if (pktbuf) { ret = err = _write(tsf, &pktbuf->pb_size, sizeof(pktbuf->pb_size)); if (err < 0) return err; err = _write(tsf, pktbuf_ptr(pktbuf), pktbuf_len(pktbuf)); if (err < 0) return err; ret += err; } else { size_t sz = 0; ret = _write(tsf, &sz, sizeof(sz)); } return ret; }
/** * Add a stream to the muxer */ static int lav_muxer_add_stream(lav_muxer_t *lm, const streaming_start_component_t *ssc) { AVStream *st; AVCodecContext *c; st = avformat_new_stream(lm->lm_oc, NULL); if (!st) return -1; st->id = ssc->ssc_index; c = st->codec; c->codec_id = streaming_component_type2codec_id(ssc->ssc_type); switch(lm->m_container) { case MC_MATROSKA: st->time_base.num = 1000000; st->time_base.den = 1; break; case MC_MPEGPS: c->rc_buffer_size = 224*1024*8; //Fall-through case MC_MPEGTS: st->time_base.num = 90000; st->time_base.den = 1; break; default: st->time_base = AV_TIME_BASE_Q; break; } if(ssc->ssc_gh) { c->extradata_size = pktbuf_len(ssc->ssc_gh); c->extradata = av_malloc(c->extradata_size); memcpy(c->extradata, pktbuf_ptr(ssc->ssc_gh), pktbuf_len(ssc->ssc_gh)); } if(SCT_ISAUDIO(ssc->ssc_type)) { c->codec_type = AVMEDIA_TYPE_AUDIO; c->sample_fmt = AV_SAMPLE_FMT_S16; c->sample_rate = sri_to_rate(ssc->ssc_sri); c->channels = ssc->ssc_channels; c->time_base.num = 1; c->time_base.den = c->sample_rate; av_dict_set(&st->metadata, "language", ssc->ssc_lang, 0); } else if(SCT_ISVIDEO(ssc->ssc_type)) { c->codec_type = AVMEDIA_TYPE_VIDEO; c->width = ssc->ssc_width; c->height = ssc->ssc_height; c->time_base.num = 1; c->time_base.den = 25; c->sample_aspect_ratio.num = ssc->ssc_aspect_num; c->sample_aspect_ratio.den = ssc->ssc_aspect_den; st->sample_aspect_ratio.num = c->sample_aspect_ratio.num; st->sample_aspect_ratio.den = c->sample_aspect_ratio.den; } else if(SCT_ISSUBTITLE(ssc->ssc_type)) { c->codec_type = AVMEDIA_TYPE_SUBTITLE; av_dict_set(&st->metadata, "language", ssc->ssc_lang, 0); } if(lm->lm_oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; return 0; }
/** * Write a packet to the muxer */ static int lav_muxer_write_pkt(muxer_t *m, streaming_message_type_t smt, void *data) { int i; AVFormatContext *oc; AVStream *st; AVPacket packet; th_pkt_t *pkt = (th_pkt_t*)data; lav_muxer_t *lm = (lav_muxer_t*)m; int rc = 0; assert(smt == SMT_PACKET); oc = lm->lm_oc; if(!oc->nb_streams) { tvhlog(LOG_ERR, "libav", "No streams to mux"); rc = -1; goto ret; } if(!lm->lm_init) { tvhlog(LOG_ERR, "libav", "Muxer not initialized correctly"); rc = -1; goto ret; } for(i=0; i<oc->nb_streams; i++) { st = oc->streams[i]; if(st->id != pkt->pkt_componentindex) continue; av_init_packet(&packet); if(st->codec->codec_id == CODEC_ID_MPEG2VIDEO) pkt = pkt_merge_header(pkt); if(lm->lm_h264_filter && st->codec->codec_id == CODEC_ID_H264) { if(av_bitstream_filter_filter(lm->lm_h264_filter, st->codec, NULL, &packet.data, &packet.size, pktbuf_ptr(pkt->pkt_payload), pktbuf_len(pkt->pkt_payload), pkt->pkt_frametype < PKT_P_FRAME) < 0) { tvhlog(LOG_WARNING, "libav", "Failed to filter bitstream"); break; } } else { 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); packet.dts = av_rescale_q(pkt->pkt_dts , mpeg_tc, st->time_base); packet.duration = av_rescale_q(pkt->pkt_duration, mpeg_tc, st->time_base); if(pkt->pkt_frametype < PKT_P_FRAME) packet.flags |= AV_PKT_FLAG_KEY; if((rc = av_interleaved_write_frame(oc, &packet))) tvhlog(LOG_WARNING, "libav", "Failed to write frame"); // h264_mp4toannexb filter might allocate new data. if(packet.data != pktbuf_ptr(pkt->pkt_payload)) av_free(packet.data); break; } ret: lm->m_errors += (rc != 0); pkt_ref_dec(pkt); return rc; }
/** * Write a packet to the muxer */ static int lav_muxer_write_pkt(muxer_t *m, streaming_message_type_t smt, void *data) { int i; AVFormatContext *oc; AVStream *st; AVPacket packet; th_pkt_t *pkt = (th_pkt_t*)data, *opkt; lav_muxer_t *lm = (lav_muxer_t*)m; unsigned char *tofree; int rc = 0; assert(smt == SMT_PACKET); oc = lm->lm_oc; if(!oc->nb_streams) { tvhlog(LOG_ERR, "libav", "No streams to mux"); rc = -1; goto ret; } if(!lm->lm_init) { tvhlog(LOG_ERR, "libav", "Muxer not initialized correctly"); rc = -1; goto ret; } for(i=0; i<oc->nb_streams; i++) { st = oc->streams[i]; if(st->id != pkt->pkt_componentindex) continue; if(pkt->pkt_payload == NULL) continue; tofree = NULL; av_init_packet(&packet); 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)) { pkt = avc_convert_pkt(opkt = pkt); pkt_ref_dec(opkt); if(av_bitstream_filter_filter(st->codec->codec_id == AV_CODEC_ID_H264 ? lm->lm_h264_filter : lm->lm_hevc_filter, st->codec, NULL, &packet.data, &packet.size, pktbuf_ptr(pkt->pkt_payload), pktbuf_len(pkt->pkt_payload), pkt->pkt_frametype < PKT_P_FRAME) < 0) { tvhlog(LOG_WARNING, "libav", "Failed to filter bitstream"); if (packet.data != pktbuf_ptr(pkt->pkt_payload)) av_free(packet.data); break; } else { tofree = packet.data; } } else if (st->codec->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 { 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); packet.dts = av_rescale_q(pkt->pkt_dts , mpeg_tc, st->time_base); packet.duration = av_rescale_q(pkt->pkt_duration, mpeg_tc, st->time_base); if(pkt->pkt_frametype < PKT_P_FRAME) packet.flags |= AV_PKT_FLAG_KEY; if((rc = av_interleaved_write_frame(oc, &packet))) tvhlog(LOG_WARNING, "libav", "Failed to write frame"); if(tofree && tofree != pktbuf_ptr(pkt->pkt_payload)) av_free(tofree); break; } ret: lm->m_errors += (rc != 0); pkt_ref_dec(pkt); return rc; }
/** * Add a stream to the muxer */ static int lav_muxer_add_stream(lav_muxer_t *lm, const streaming_start_component_t *ssc) { AVStream *st; AVCodecContext *c; st = avformat_new_stream(lm->lm_oc, NULL); if (!st) return -1; st->id = ssc->ssc_index; c = st->codec; c->codec_id = streaming_component_type2codec_id(ssc->ssc_type); 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; case MC_MPEGPS: c->rc_buffer_size = 224*1024*8; //Fall-through case MC_MPEGTS: st->time_base.num = 90000; st->time_base.den = 1; break; default: st->time_base = AV_TIME_BASE_Q; break; } if(ssc->ssc_gh) { if (ssc->ssc_type == SCT_H264 || ssc->ssc_type == SCT_HEVC) { sbuf_t hdr; sbuf_init(&hdr); if (ssc->ssc_type == SCT_H264) { isom_write_avcc(&hdr, pktbuf_ptr(ssc->ssc_gh), pktbuf_len(ssc->ssc_gh)); } else { isom_write_hvcc(&hdr, pktbuf_ptr(ssc->ssc_gh), pktbuf_len(ssc->ssc_gh)); } c->extradata_size = hdr.sb_ptr; c->extradata = av_malloc(hdr.sb_ptr); memcpy(c->extradata, hdr.sb_data, hdr.sb_ptr); sbuf_free(&hdr); } else { c->extradata_size = pktbuf_len(ssc->ssc_gh); c->extradata = av_malloc(c->extradata_size); memcpy(c->extradata, pktbuf_ptr(ssc->ssc_gh), pktbuf_len(ssc->ssc_gh)); } } if(SCT_ISAUDIO(ssc->ssc_type)) { c->codec_type = AVMEDIA_TYPE_AUDIO; c->sample_fmt = AV_SAMPLE_FMT_S16; c->sample_rate = sri_to_rate(ssc->ssc_sri); c->channels = ssc->ssc_channels; #if 0 c->time_base.num = 1; c->time_base.den = c->sample_rate; #else c->time_base = st->time_base; #endif av_dict_set(&st->metadata, "language", ssc->ssc_lang, 0); } else if(SCT_ISVIDEO(ssc->ssc_type)) { c->codec_type = AVMEDIA_TYPE_VIDEO; c->width = ssc->ssc_width; c->height = ssc->ssc_height; c->time_base.num = 1; c->time_base.den = 25; c->sample_aspect_ratio.num = ssc->ssc_aspect_num; c->sample_aspect_ratio.den = ssc->ssc_aspect_den; if (lm->m_config.m_type == MC_AVMP4) { /* this is a whole hell */ AVRational ratio = { c->height, c->width }; c->sample_aspect_ratio = av_mul_q(c->sample_aspect_ratio, ratio); } st->sample_aspect_ratio.num = c->sample_aspect_ratio.num; st->sample_aspect_ratio.den = c->sample_aspect_ratio.den; } else if(SCT_ISSUBTITLE(ssc->ssc_type)) { c->codec_type = AVMEDIA_TYPE_SUBTITLE; av_dict_set(&st->metadata, "language", ssc->ssc_lang, 0); } if(lm->lm_oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; return 0; }