return FALSE;
}
-
+#ifdef TIZEN_FEATURE_LIBAV
+/* trailer entry size */
+#define ENTRY_SIZE_VIDEO_STTS 8
+#define ENTRY_SIZE_VIDEO_STSS 4
+#define ENTRY_SIZE_VIDEO_STSZ 4
+#define ENTRY_SIZE_VIDEO_STCO 4
+#define ENTRY_SIZE_AUDIO_STTS 8
+#define ENTRY_SIZE_AUDIO_STSZ 4
+#define ENTRY_SIZE_AUDIO_STCO 4
+
+#define ENTRY_SIZE_VIDEO_MPEG4_STSD 146
+#define ENTRY_SIZE_VIDEO_H263P_STSD 102
+#define ENTRY_SIZE_AUDIO_AAC_STSD 106
+#define ENTRY_SIZE_AUDIO_AMR_STSD 69
+
+#define ENTRY_SIZE_STSC 12
+#define ENTRY_SIZE_VIDEO_ST 84 /*atom size (stss + stts + stsc + stsz + stco ) * (size + atom + version + flags + sample count)+stsz(sample size) */
+#define ENTRY_SIZE_AUDIO_ST 68 /*atom size (stss + stsc + stsz + stco ) * (size + atom + version + flags + sample count)+stsz(sample size) */
+
-
+/* ffmux_adts */
+#define MUX_ADTS_NAME "adts"
+#define MUX_AMR_NAME "amr"
+#define MUX_MP4_NAME "mp4"
+#define MUX_ADTS_SIZE_HEADER 8
+#define MUX_ADTS_SIZE_ENTRY 7
+#define MUX_AMR_SIZE_HEADER 6
+
+/* common */
+#define MUX_COMMON_SIZE_3GP_HEADER 290 /* ftyp + free + moov + mvhd + +iods + udta */
+#define MUX_COMMON_SIZE_MP4_HEADER 378 /* ftyp + free + moov + mvhd + +iods + udta (meta) */
+#define MUX_COMMON_SIZE_MP4_VIDEO_HEADER 305
+#define MUX_COMMON_SIZE_MP4_AUDIO_HEADER 253
+
+#define MUX_INFO_SIZE_LOCATION 106 /* loci + .xyz */
+
-
-
+static void
+update_expected_trailer_size (GstFFMpegMux * ffmpegmux)
+{
+ int i = 0;
+ guint nb_video_frames = 0;
+ guint nb_video_i_frames = 0;
+ guint nb_video_stts_entry = 0;
+ guint nb_audio_frames = 0;
+ guint nb_audio_stts_entry = 0;
+ gboolean video_stream = FALSE;
+ gboolean audio_stream = FALSE;
+ guint exp_size = 0;
+ AVCodecContext *codec_context = NULL;
+ enum AVCodecID video_codec_id;
+ enum AVCodecID audio_codec_id;
+
+ if (ffmpegmux == NULL) {
+ GST_WARNING ("ffmpegmux is NULL");
+ return;
+ }
+
+ for (i = 0; i < ffmpegmux->context->nb_streams; i++) {
+ codec_context = ffmpegmux->context->streams[i]->codec;
+ if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO) {
+ nb_video_frames += codec_context->frame_number;
+ nb_video_i_frames += codec_context->i_frame_number;
+ nb_video_stts_entry += codec_context->stts_count;
+
+ video_stream = TRUE;
+ video_codec_id = codec_context->codec_id;
+ } else if (codec_context->codec_type == AVMEDIA_TYPE_AUDIO) {
+ nb_audio_frames += codec_context->frame_number;
+ nb_audio_stts_entry += codec_context->stts_count;
+
+ audio_stream = TRUE;
+ audio_codec_id = codec_context->codec_id;
+ }
+ }
+
+ /*
+ [[ Metadata Size ]]
+ - COMMON
+ ftyp = 28 (MPEG4 ftype: 28 , H263P fype: 28)
+ free = 8
+ moov = 8
+ mvhd = 108
+ iods = 24
+ **optional
+ udta = 114(meta in case of audio only) or
+ 114(loci in case of video only or video/audio) or
+ 202( with meta in MP4)
+ 96 ( audio only with meta )
+
+ total : 290 (3GP) or 378 (MP4)
+
+ - VIDEO:MPEG4
+ trak = 8
+ tkhd = 92
+ edts = 48 ( addition )
+ mdia = 8
+ mdhd = 32
+ hdir = 45
+ minf = 8
+ vmhd = 20
+ dinf = 36 ( 8 , dref : 16 , url : 12 )
+ stbl = 8 ( common video total : 305 )
+ stsd = 146 ( addtion : 16 + , mp4v: 86 ,esds : 44 )
+ stts = 16 + (8*stts_count)
+ stss = 16 + (4*I-frame)
+ stsc = 28
+ stsz = 20 + (4*frame)
+ stco = 16 + (4*frame)
+
+ - VIDEO:H.264 = 487(or 489) + (8*stts_count) + (8*frame) + (4*I-frame)
+ trak = 8
+ tkhd = 92
+ edts = 48 ( addition )
+ mdia = 8
+ mdhd = 32
+ hdir = 45
+ minf = 8
+ vmhd = 20
+ dinf = 36 ( 8 , dref : 16 , url : 12 )
+ stbl = 8
+ stsd = 134 (SPS 9, PPS 4) or 136 (SPS 111, PPS 4)
+ stts = 16 + (8*stts_count)
+ stss = 16 + (4*I-frame)
+ stsc = 28
+ stsz = 20 + (4*frame)
+ stco = 16 + (4*frame)
+
+ - VIDEO:H.263 = 470 + + (8*stts_count) + (8*frame) + (4*I-frame)
+ trak = 8
+ tkhd = 92
+ edts = 48 ( addition )
+ mdia = 8
+ mdhd = 32
+ hdir = 45
+ minf = 8
+ vmhd = 20
+ dinf = 36
+ stbl = 8
+ stsd = 102 -> different from H.264
+ stts = 16 + (8*stts_count)
+ stss = 16 + (4*I-frame)
+ stsc = 28
+ stsz = 20 + (4*frame)
+ stco = 16 + (4*frame)
+
+ - AUDIO:AAC = 424 + + (8*stts_count) + (8*audio_frame)
+ trak = 8
+ tkhd = 92
+ mdia = 8
+ mdhd = 32
+ hdir = 45
+ minf = 8
+ smhd = 16
+ dinf = 36 ( 8 , dref : 16 , url : 12 )
+ stbl = 8 ( common video total : 253 )
+ stsd = 106 + ( addtion : 16 , mp4v: 46 ,esds : 54 )
+ stts = 16 + (8*stts_count)
+ stsc = 28
+ stsz = 20 + (4*frame)
+ stco = 16 + (4*frame)
+
+ - AUDIO:AMR = 410 + (4*audio_frame)
+ trak = 8
+ tkhd = 92
+ mdia = 8
+ mdhd = 32
+ hdir = 45
+ minf = 8
+ smhd = 16
+ dinf = 36
+ stbl = 8
+ stsd = 69 -> different from AAC
+ stts = 24 -> different from AAC
+ stsc = 28
+ stsz = 20 -> different from AAC
+ stco = 16 + (4*frame)
+ */
+
+ /* Calculate trailer size for video stream */
+ if (!strcmp (ffmpegmux->context->oformat->name, MUX_ADTS_NAME)) {
+
+ } else if (!strcmp (ffmpegmux->context->oformat->name, MUX_ADTS_NAME)) {
+
+ } else if (!strcmp (ffmpegmux->context->oformat->name, MUX_MP4_NAME)) {
+ exp_size = MUX_COMMON_SIZE_MP4_HEADER;
+ } else {
+ exp_size = MUX_COMMON_SIZE_3GP_HEADER;
+ }
+ //GST_INFO_OBJECT(ffmpegmux, "size: common size=[%d]", exp_size);
+
+ if (video_stream) {
+ /* ftyp + free + moov + mvhd + udta : H.264 -> 240, H.263 -> 236 */
+ /* trak size except frame related : H.264 -> 489, H.263 -> 470 */
+ if (video_codec_id == AV_CODEC_ID_H263
+ || video_codec_id == AV_CODEC_ID_H263P) {
+ exp_size +=
+ MUX_COMMON_SIZE_MP4_VIDEO_HEADER + ENTRY_SIZE_VIDEO_H263P_STSD;
+ } else if (video_codec_id == AV_CODEC_ID_MPEG4) {
+ exp_size +=
+ MUX_COMMON_SIZE_MP4_VIDEO_HEADER + ENTRY_SIZE_VIDEO_MPEG4_STSD;
+ } else {
+ exp_size += 240 + 489;
+ }
+
+ //GST_INFO_OBJECT(ffmpegmux, "size: [%d]",exp_size);
+
+ /* frame related */
+ exp_size +=
+ ENTRY_SIZE_VIDEO_ST + (ENTRY_SIZE_VIDEO_STTS * nb_video_stts_entry) +
+ (ENTRY_SIZE_VIDEO_STSS * nb_video_i_frames) + (ENTRY_SIZE_STSC) +
+ ((ENTRY_SIZE_VIDEO_STSZ + ENTRY_SIZE_VIDEO_STCO) * nb_video_frames);
+ }
+ //GST_INFO_OBJECT(ffmpegmux, "size: video=[%d] size=[%d], stts-entry=[%d], i-frame=[%d], video-sample=[%d]", video_stream, exp_size,nb_video_stts_entry,nb_video_i_frames,nb_video_frames);
+
+ if (audio_stream) {
+ /* Calculate trailer size for audio stream */
+ if (!strcmp (ffmpegmux->context->oformat->name, MUX_ADTS_NAME)) {
+ /* avmux_adts */
+ exp_size +=
+ MUX_ADTS_SIZE_HEADER + (MUX_ADTS_SIZE_ENTRY * nb_audio_frames);
+ } else if (!strcmp (ffmpegmux->context->oformat->name, MUX_AMR_NAME)) {
+ /* only audio avmux_amr */
+ exp_size = MUX_AMR_SIZE_HEADER;
+ } else {
+ /* avmux_3gp , avmux_mp4 */
+ if (!video_stream) {
+ /* audio only does not contain location info now */
+ exp_size -= MUX_INFO_SIZE_LOCATION;
+ }
+ /* others - avmux_3gp/mp4/amr */
+ if (audio_codec_id == AV_CODEC_ID_AMR_NB) {
+ /* AMR_NB codec */
+ exp_size +=
+ MUX_COMMON_SIZE_MP4_AUDIO_HEADER + ENTRY_SIZE_AUDIO_AMR_STSD;
+
+ //GST_INFO_OBJECT(ffmpegmux, "size: [%d]",exp_size);
+
+ exp_size +=
+ ENTRY_SIZE_AUDIO_ST +
+ (ENTRY_SIZE_AUDIO_STTS * nb_audio_stts_entry) + (ENTRY_SIZE_STSC) +
+ (ENTRY_SIZE_AUDIO_STCO * nb_audio_frames);
+ } else {
+ /* AAC codec */
+ exp_size +=
+ MUX_COMMON_SIZE_MP4_AUDIO_HEADER + ENTRY_SIZE_AUDIO_AAC_STSD;
+
+ //GST_INFO_OBJECT(ffmpegmux, "size: [%d]",exp_size);
+
+ exp_size +=
+ ENTRY_SIZE_AUDIO_ST +
+ (ENTRY_SIZE_AUDIO_STTS * nb_audio_stts_entry) + (ENTRY_SIZE_STSC) +
+ ((ENTRY_SIZE_AUDIO_STSZ + ENTRY_SIZE_AUDIO_STCO) * nb_audio_frames);
+ }
+
+ }
+ }
+ //GST_INFO_OBJECT(ffmpegmux, "size: audio=[%d], size=[%d], stts-entry=[%d], audio-sample=[%d]", audio_stream, exp_size, nb_audio_stts_entry, nb_audio_frames);
+
+ ffmpegmux->expected_trailer_size = exp_size;
+ ffmpegmux->nb_video_frames = nb_video_frames;
+ ffmpegmux->nb_audio_frames = nb_audio_frames;
+
+ return;
+}
+#endif /* TIZEN_FEATURE_LIBAV */
+
-
static void
gst_ffmpegmux_base_init (gpointer g_class)
{
ffmpegmux->videopads = 0;
ffmpegmux->audiopads = 0;
ffmpegmux->max_delay = 0;
-
+
+#ifdef TIZEN_FEATURE_LIBAV
+ ffmpegmux->expected_trailer_size = 0;
+ ffmpegmux->nb_video_frames = 0;
+ ffmpegmux->nb_audio_frames = 0;
+#endif /* TIZEN_FEATURE_LIBAV */
+}
+
+#ifdef TIZEN_FEATURE_LIBAV
+static void
+gst_ffmpegmux_release_pad (GstElement * element, GstPad * pad)
+{
+ GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) element;
+ GstFFMpegMuxPad *collect_pad;
+ AVStream *st;
+ int i;
+ collect_pad = (GstFFMpegMuxPad *)gst_pad_get_element_private(pad);
+
+ GST_DEBUG ("Release requested pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
+ st = ffmpegmux->context->streams[collect_pad->padnum];
+ if (st) {
+ if (st->codec) {
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ ffmpegmux->videopads--;
+ } else {
+ ffmpegmux->audiopads--;
+ }
+ if (st->codec->extradata) {
+ av_free(st->codec->extradata);
+ st->codec->extradata = NULL;
+ }
+ g_free(st->codec);
+ st->codec = NULL;
+ }
+ if (ffmpegmux->context->priv_data) {
+ MOVMuxContext *mov = ffmpegmux->context->priv_data;
+ if (mov && mov->tracks) {
+ for (i = 0 ; i < ffmpegmux->context->nb_streams ; i++) {
+ MOVTrack *trk = &mov->tracks[i];
+ if (trk && trk->vos_data) {
+ av_free(trk->vos_data);
+ trk->vos_data = NULL;
+ }
+ }
+ av_free(mov->tracks);
+ mov->tracks = NULL;
+ }
+ av_free(ffmpegmux->context->priv_data);
+ ffmpegmux->context->priv_data = NULL;
+ }
+ ffmpegmux->context->nb_streams--;
+ g_free(st);
+ st = NULL;
+ }
+ gst_collect_pads_remove_pad(ffmpegmux->collect, pad);
+ gst_element_remove_pad(element, pad);
+
+ return;
}
+#endif /* TIZEN_FEATURE_LIBAV */
static void
gst_ffmpegmux_set_property (GObject * object, guint prop_id,
/* for the format-specific guesses, we'll go to
* our famous codec mapper */
- if (gst_ffmpeg_caps_to_codecid (caps, st->codec) == AV_CODEC_ID_NONE)
+ if (gst_ffmpeg_caps_to_codecid (caps, &tmp) == AV_CODEC_ID_NONE)
goto not_accepted;
+ avcodec_parameters_from_context (st->codecpar, &tmp);
+
/* copy over the aspect ratios, ffmpeg expects the stream aspect to match the
* codec aspect. */
- st->sample_aspect_ratio = st->codec->sample_aspect_ratio;
+ st->sample_aspect_ratio = st->codecpar->sample_aspect_ratio;
+#ifdef TIZEN_FEATURE_LIBAV
+ /* ref counting bug fix */
+ gst_object_unref(ffmpegmux);
+#endif /* TIZEN_FEATURE_LIBAV */
+
GST_LOG_OBJECT (pad, "accepted caps %" GST_PTR_FORMAT, caps);
return TRUE;
if (best_pad != NULL) {
GstBuffer *buf;
AVPacket pkt;
- gboolean need_free = FALSE;
GstMapInfo map;
+#ifdef TIZEN_FEATURE_LIBAV
+ av_init_packet (&pkt);
+ pkt.is_mux = 1;
+#endif /* TIZEN_FEATURE_LIBAV */
+
/* push out current buffer */
buf =
gst_collect_pads_pop (ffmpegmux->collect, (GstCollectData *) best_pad);
- ffmpegmux->context->streams[best_pad->padnum]->codec->frame_number++;
-
/* set time */
+#ifdef TIZEN_FEATURE_LIBAV
+ if (ffmpegmux->context->streams[best_pad->padnum]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ pkt.pts = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buf));
+ else
+#else /* TIZEN_FEATURE_LIBAV */
pkt.pts = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buf),
ffmpegmux->context->streams[best_pad->padnum]->time_base);
+#endif /* TIZEN_FEATURE_LIBAV */
pkt.dts = pkt.pts;
- if (strcmp (ffmpegmux->context->oformat->name, "gif") == 0) {
- AVStream *st = ffmpegmux->context->streams[best_pad->padnum];
- AVPicture src, dst;
-
- need_free = TRUE;
- pkt.size = st->codec->width * st->codec->height * 3;
- pkt.data = g_malloc (pkt.size);
-
- dst.data[0] = pkt.data;
- dst.data[1] = NULL;
- dst.data[2] = NULL;
- dst.linesize[0] = st->codec->width * 3;
-
- gst_buffer_map (buf, &map, GST_MAP_READ);
- gst_ffmpeg_avpicture_fill (&src, map.data,
- AV_PIX_FMT_RGB24, st->codec->width, st->codec->height);
-
- av_picture_copy (&dst, &src, AV_PIX_FMT_RGB24,
- st->codec->width, st->codec->height);
- gst_buffer_unmap (buf, &map);
- } else {
- gst_buffer_map (buf, &map, GST_MAP_READ);
- pkt.data = map.data;
- pkt.size = map.size;
- }
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ pkt.data = map.data;
+ pkt.size = map.size;
pkt.stream_index = best_pad->padnum;
pkt.flags = 0;
ffmpegmux->context->streams[best_pad->padnum]->time_base);
else
pkt.duration = 0;
+#endif /* TIZEN_FEATURE_LIBAV */
av_write_frame (ffmpegmux->context, &pkt);
- if (need_free) {
- g_free (pkt.data);
- } else {
- gst_buffer_unmap (buf, &map);
- }
+ gst_buffer_unmap (buf, &map);
gst_buffer_unref (buf);
} else {
/* close down */