Merge commit 'f6c82b34a320f105af266997f5951cbe7dfc8a05' into release/2.4
authorMichael Niedermayer <michaelni@gmx.at>
Sat, 17 Jan 2015 21:56:52 +0000 (22:56 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 17 Jan 2015 21:56:52 +0000 (22:56 +0100)
* commit 'f6c82b34a320f105af266997f5951cbe7dfc8a05':
  segment: Fix the failure paths

Conflicts:
libavformat/segment.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavformat/segment.c

@@@ -498,69 -177,19 +498,76 @@@ static int open_null_ctx(AVIOContext **
      return 0;
  }
  
 -static void close_null_ctx(AVIOContext *pb)
 +static void close_null_ctxp(AVIOContext **pb)
 +{
 +    av_freep(&(*pb)->buffer);
 +    av_freep(pb);
 +}
 +
 +static int select_reference_stream(AVFormatContext *s)
  {
 -    av_free(pb->buffer);
 -    av_free(pb);
 +    SegmentContext *seg = s->priv_data;
 +    int ret, i;
 +
 +    seg->reference_stream_index = -1;
 +    if (!strcmp(seg->reference_stream_specifier, "auto")) {
 +        /* select first index of type with highest priority */
 +        int type_index_map[AVMEDIA_TYPE_NB];
 +        static const enum AVMediaType type_priority_list[] = {
 +            AVMEDIA_TYPE_VIDEO,
 +            AVMEDIA_TYPE_AUDIO,
 +            AVMEDIA_TYPE_SUBTITLE,
 +            AVMEDIA_TYPE_DATA,
 +            AVMEDIA_TYPE_ATTACHMENT
 +        };
 +        enum AVMediaType type;
 +
 +        for (i = 0; i < AVMEDIA_TYPE_NB; i++)
 +            type_index_map[i] = -1;
 +
 +        /* select first index for each type */
 +        for (i = 0; i < s->nb_streams; i++) {
 +            type = s->streams[i]->codec->codec_type;
 +            if ((unsigned)type < AVMEDIA_TYPE_NB && type_index_map[type] == -1
 +                /* ignore attached pictures/cover art streams */
 +                && !(s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC))
 +                type_index_map[type] = i;
 +        }
 +
 +        for (i = 0; i < FF_ARRAY_ELEMS(type_priority_list); i++) {
 +            type = type_priority_list[i];
 +            if ((seg->reference_stream_index = type_index_map[type]) >= 0)
 +                break;
 +        }
 +    } else {
 +        for (i = 0; i < s->nb_streams; i++) {
 +            ret = avformat_match_stream_specifier(s, s->streams[i],
 +                                                  seg->reference_stream_specifier);
 +            if (ret < 0)
 +                return ret;
 +            if (ret > 0) {
 +                seg->reference_stream_index = i;
 +                break;
 +            }
 +        }
 +    }
 +
 +    if (seg->reference_stream_index < 0) {
 +        av_log(s, AV_LOG_ERROR, "Could not select stream matching identifier '%s'\n",
 +               seg->reference_stream_specifier);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    return 0;
  }
  
 -    avio_closep(&seg->pb);
+ static void seg_free_context(SegmentContext *seg)
+ {
++    avio_closep(&seg->list_pb);
+     avformat_free_context(seg->avf);
+     seg->avf = NULL;
+ }
  static int seg_write_header(AVFormatContext *s)
  {
      SegmentContext *seg = s->priv_data;
              goto fail;
      }
  
 -    if (seg->list) {
 -        if (seg->list_type == LIST_HLS) {
 -            if ((ret = segment_hls_window(s, 0)) < 0)
 -                goto fail;
 -        } else {
 -            avio_printf(seg->pb, "%s\n", oc->filename);
 -            avio_flush(seg->pb);
 -        }
 -    }
 -
  fail:
-     if (ret) {
-         if (seg->list)
-             avio_close(seg->list_pb);
-         if (seg->avf)
-             avformat_free_context(seg->avf);
-     }
 +    av_dict_free(&options);
+     if (ret < 0)
+         seg_free_context(seg);
      return ret;
  }
  
  static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
  {
      SegmentContext *seg = s->priv_data;
 -    AVFormatContext *oc = seg->avf;
      AVStream *st = s->streams[pkt->stream_index];
 -    int64_t end_pts = seg->recording_time * seg->number;
 -    int ret, can_split = 1;
 -
 -    if (!oc)
 +    int64_t end_pts = INT64_MAX, offset;
 +    int start_frame = INT_MAX;
 +    int ret;
 +    struct tm ti;
 +    int64_t usecs;
 +    int64_t wrapped_val;
 +
++    if (!seg->avf)
+         return AVERROR(EINVAL);
 -    if (seg->has_video) {
 -        can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
 -                    pkt->flags & AV_PKT_FLAG_KEY;
 +    if (seg->times) {
 +        end_pts = seg->segment_count < seg->nb_times ?
 +            seg->times[seg->segment_count] : INT64_MAX;
 +    } else if (seg->frames) {
 +        start_frame = seg->segment_count < seg->nb_frames ?
 +            seg->frames[seg->segment_count] : INT_MAX;
 +    } else {
 +        if (seg->use_clocktime) {
 +            int64_t avgt = av_gettime();
 +            time_t sec = avgt / 1000000;
 +#if HAVE_LOCALTIME_R
 +            localtime_r(&sec, &ti);
 +#else
 +            ti = *localtime(&sec);
 +#endif
 +            usecs = (int64_t)(ti.tm_hour*3600 + ti.tm_min*60 + ti.tm_sec) * 1000000 + (avgt % 1000000);
 +            wrapped_val = usecs % seg->time;
 +            if (seg->last_cut != usecs && wrapped_val < seg->last_val) {
 +                seg->cut_pending = 1;
 +                seg->last_cut = usecs;
 +            }
 +            seg->last_val = wrapped_val;
 +        } else {
 +            end_pts = seg->time * (seg->segment_count+1);
 +        }
      }
  
 -    if (can_split && av_compare_ts(pkt->pts, st->time_base, end_pts,
 -                                   AV_TIME_BASE_Q) >= 0) {
 -        av_log(s, AV_LOG_DEBUG, "Next segment starts at %d %"PRId64"\n",
 -               pkt->stream_index, pkt->pts);
 -
 -        ret = segment_end(oc, seg->individual_header_trailer);
 -
 -        if (!ret)
 -            ret = segment_start(s, seg->individual_header_trailer);
 +    av_dlog(s, "packet stream:%d pts:%s pts_time:%s duration_time:%s is_key:%d frame:%d\n",
 +            pkt->stream_index, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
 +            av_ts2timestr(pkt->duration, &st->time_base),
 +            pkt->flags & AV_PKT_FLAG_KEY,
 +            pkt->stream_index == seg->reference_stream_index ? seg->frame_count : -1);
 +
 +    if (pkt->stream_index == seg->reference_stream_index &&
 +        pkt->flags & AV_PKT_FLAG_KEY &&
 +        seg->segment_frame_count > 0 &&
 +        (seg->cut_pending || seg->frame_count >= start_frame ||
 +         (pkt->pts != AV_NOPTS_VALUE &&
 +          av_compare_ts(pkt->pts, st->time_base,
 +                        end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0))) {
 +        /* sanitize end time in case last packet didn't have a defined duration */
 +        if (seg->cur_entry.last_duration == 0)
 +            seg->cur_entry.end_time = (double)pkt->pts * av_q2d(st->time_base);
 +
 +        if ((ret = segment_end(s, seg->individual_header_trailer, 0)) < 0)
 +            goto fail;
  
 -        if (ret)
 +        if ((ret = segment_start(s, seg->individual_header_trailer)) < 0)
              goto fail;
  
 -        oc = seg->avf;
 +        seg->cut_pending = 0;
 +        seg->cur_entry.index = seg->segment_idx + seg->segment_idx_wrap*seg->segment_idx_wrap_nb;
 +        seg->cur_entry.start_time = (double)pkt->pts * av_q2d(st->time_base);
 +        seg->cur_entry.start_pts = av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q);
 +        seg->cur_entry.end_time = seg->cur_entry.start_time +
 +            pkt->pts != AV_NOPTS_VALUE ? (double)(pkt->pts + pkt->duration) * av_q2d(st->time_base) : 0;
 +    } else if (pkt->pts != AV_NOPTS_VALUE && pkt->stream_index == seg->reference_stream_index) {
 +        seg->cur_entry.end_time =
 +            FFMAX(seg->cur_entry.end_time, (double)(pkt->pts + pkt->duration) * av_q2d(st->time_base));
 +        seg->cur_entry.last_duration = pkt->duration;
 +    }
  
 -        if (seg->list) {
 -            if (seg->list_type == LIST_HLS) {
 -                if ((ret = segment_hls_window(s, 0)) < 0)
 -                    goto fail;
 -            } else {
 -                avio_printf(seg->pb, "%s\n", oc->filename);
 -                avio_flush(seg->pb);
 -                if (seg->size && !(seg->number % seg->size)) {
 -                    avio_closep(&seg->pb);
 -                    if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
 -                                          &s->interrupt_callback, NULL)) < 0)
 -                        goto fail;
 -                }
 -            }
 -        }
 +    if (seg->segment_frame_count == 0) {
 +        av_log(s, AV_LOG_VERBOSE, "segment:'%s' starts with packet stream:%d pts:%s pts_time:%s frame:%d\n",
 +               seg->avf->filename, pkt->stream_index,
 +               av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), seg->frame_count);
      }
  
 -    ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
 +    av_log(s, AV_LOG_DEBUG, "stream:%d start_pts_time:%s pts:%s pts_time:%s dts:%s dts_time:%s",
 +           pkt->stream_index,
 +           av_ts2timestr(seg->cur_entry.start_pts, &AV_TIME_BASE_Q),
 +           av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
 +           av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
 +
 +    /* compute new timestamps */
 +    offset = av_rescale_q(seg->initial_offset - (seg->reset_timestamps ? seg->cur_entry.start_pts : 0),
 +                          AV_TIME_BASE_Q, st->time_base);
 +    if (pkt->pts != AV_NOPTS_VALUE)
 +        pkt->pts += offset;
 +    if (pkt->dts != AV_NOPTS_VALUE)
 +        pkt->dts += offset;
 +
 +    av_log(s, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n",
 +           av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
 +           av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
 +
 +    ret = ff_write_chained(seg->avf, pkt->stream_index, pkt, s, seg->initial_offset || seg->reset_timestamps);
  
  fail:
 +    if (pkt->stream_index == seg->reference_stream_index) {
 +        seg->frame_count++;
 +        seg->segment_frame_count++;
 +    }
 +
+     if (ret < 0)
+         seg_free_context(seg);
      return ret;
  }
  
@@@ -813,11 -338,13 +823,14 @@@ static int seg_write_trailer(struct AVF
  {
      SegmentContext *seg = s->priv_data;
      AVFormatContext *oc = seg->avf;
 +    SegmentListEntry *cur, *next;
+     int ret = 0;
+     if (!oc)
+         goto fail;
  
-     int ret;
      if (!seg->write_header_trailer) {
 -        if ((ret = segment_end(oc, 0)) < 0)
 +        if ((ret = segment_end(s, 0, 1)) < 0)
              goto fail;
          open_null_ctx(&oc->pb);
          ret = av_write_trailer(oc);