Ticket #1483: 0001-lavf-segment-add-segment_frames-option.patch
| File 0001-lavf-segment-add-segment_frames-option.patch, 9.0 KB (added by saste, 5 months ago) |
|---|
-
doc/muxers.texi
From 57f9b7f208567b4f3cdfa6125a3b4b767e474897 Mon Sep 17 00:00:00 2001 From: Stefano Sabatini <stefasab@gmail.com> Date: Sun, 9 Dec 2012 20:26:30 +0100 Subject: [PATCH] lavf/segment: add segment_frames option This is meant to address trac ticket #1483. --- doc/muxers.texi | 15 +++++++ libavformat/segment.c | 103 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 106 insertions(+), 12 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index 25cf565..763b172 100644
a b the specified time and the time set by @var{force_key_frames}. 599 599 Specify a list of split points. @var{times} contains a list of comma 600 600 separated duration specifications, in increasing order. 601 601 602 @item segment_frames @var{frames} 603 Specify a list of split video frame numbers. @var{frames} contains a 604 list of comma separated integer numbers, in increasing order. 605 606 This option specifies to start a new segment whenever a video key 607 frame is found and the sequential number (starting from 0) of the 608 video frame is greater or equal to the next value in the list. 609 602 610 @item segment_wrap @var{limit} 603 611 Wrap around segment index once it reaches @var{limit}. 604 612 … … In order to force key frames on the input file, transcoding is 643 651 required. 644 652 645 653 @item 654 Segment the input file by splitting the input file according to the 655 frame numbers sequence specified with the @var{segment_frame} option: 656 @example 657 ffmpeg -i in.mkv -codec copy -map 0 -f segment -segment_list out.csv -segment_frames 100,200,300,500,800 out%03d.nut 658 @end example 659 660 @item 646 661 To convert the @file{in.mkv} to TS segments using the @code{libx264} 647 662 and @code{libfaac} encoders: 648 663 @example -
libavformat/segment.c
diff --git a/libavformat/segment.c b/libavformat/segment.c index dc9b9c8..801fd42 100644
a b typedef enum { 45 45 LIST_TYPE_NB, 46 46 } ListType; 47 47 48 49 48 #define SEGMENT_LIST_FLAG_CACHE 1 50 49 #define SEGMENT_LIST_FLAG_LIVE 2 51 50 … … typedef struct { 65 64 AVIOContext *list_pb; ///< list file put-byte context 66 65 char *time_str; ///< segment duration specification string 67 66 int64_t time; ///< segment duration 67 68 68 char *times_str; ///< segment times specification string 69 69 int64_t *times; ///< list of segment interval specification 70 70 int nb_times; ///< number of elments in the times array 71 72 char *frames_str; ///< segment frame numbers specification string 73 int *frames; ///< list of frame number specification 74 int nb_frames; ///< number of elments in the frames array 75 int frame_count; 76 71 77 char *time_delta_str; ///< approximation value duration used for the segment times 72 78 int64_t time_delta; 73 79 int individual_header_trailer; /**< Set by a private option. */ … … end: 318 324 return ret; 319 325 } 320 326 327 static int parse_frames(void *log_ctx, int **frames, int *nb_frames, 328 const char *frames_str) 329 { 330 char *p; 331 int i, ret = 0; 332 char *frames_str1 = av_strdup(frames_str); 333 char *saveptr = NULL; 334 335 if (!frames_str1) 336 return AVERROR(ENOMEM); 337 338 #define FAIL(err) ret = err; goto end 339 340 *nb_frames = 1; 341 for (p = frames_str1; *p; p++) 342 if (*p == ',') 343 (*nb_frames)++; 344 345 *frames = av_malloc(sizeof(**frames) * *nb_frames); 346 if (!*frames) { 347 av_log(log_ctx, AV_LOG_ERROR, "Could not allocate forced frames array\n"); 348 FAIL(AVERROR(ENOMEM)); 349 } 350 351 p = frames_str1; 352 for (i = 0; i < *nb_frames; i++) { 353 long int f; 354 char *tailptr; 355 char *fstr = av_strtok(p, ",", &saveptr); 356 357 p = NULL; 358 if (!fstr) { 359 av_log(log_ctx, AV_LOG_ERROR, "Empty frame specification in frame list %s\n", 360 frames_str); 361 FAIL(AVERROR(EINVAL)); 362 } 363 f = strtol(fstr, &tailptr, 10); 364 if (*tailptr || f <= 0 || f >= INT_MAX) { 365 av_log(log_ctx, AV_LOG_ERROR, 366 "Invalid argument '%s', must be a positive integer <= INT64_MAX\n", 367 fstr); 368 FAIL(AVERROR(EINVAL)); 369 } 370 (*frames)[i] = f; 371 372 /* check on monotonicity */ 373 if (i && (*frames)[i-1] > (*frames)[i]) { 374 av_log(log_ctx, AV_LOG_ERROR, 375 "Specified frame %d is greater than the following frame %d\n", 376 (*frames)[i], (*frames)[i-1]); 377 FAIL(AVERROR(EINVAL)); 378 } 379 } 380 381 end: 382 av_free(frames_str1); 383 return ret; 384 } 385 321 386 static int open_null_ctx(AVIOContext **ctx) 322 387 { 323 388 int buf_size = 32768; … … static int seg_write_header(AVFormatContext *s) 348 413 if (!seg->write_header_trailer) 349 414 seg->individual_header_trailer = 0; 350 415 351 if ( seg->time_str && seg->times_str) {416 if (!!seg->time_str + !!seg->times_str + !!seg->frames_str > 1) { 352 417 av_log(s, AV_LOG_ERROR, 353 "segment_time and segment_times options are mutually exclusive, select just one of them\n"); 418 "segment_time, segment_times, and segment_frames options " 419 "are mutually exclusive, select just one of them\n"); 354 420 return AVERROR(EINVAL); 355 421 } 356 422 357 if ((seg->list_flags & SEGMENT_LIST_FLAG_LIVE) && seg->times_str) {423 if ((seg->list_flags & SEGMENT_LIST_FLAG_LIVE) && (seg->times_str || seg->frames_str)) { 358 424 av_log(s, AV_LOG_ERROR, 359 "segment_flags +live and segment_times o ptions are mutually exclusive:"360 "specify -segment_timeif you want a live-friendly list\n");425 "segment_flags +live and segment_times or segment_frames options are mutually exclusive: " 426 "specify segment_time option if you want a live-friendly list\n"); 361 427 return AVERROR(EINVAL); 362 428 } 363 429 364 430 if (seg->times_str) { 365 431 if ((ret = parse_times(s, &seg->times, &seg->nb_times, seg->times_str)) < 0) 366 432 return ret; 433 } else if (seg->frames_str) { 434 if ((ret = parse_frames(s, &seg->frames, &seg->nb_frames, seg->frames_str)) < 0) 435 return ret; 367 436 } else { 368 437 /* set default value if not specified */ 369 438 if (!seg->time_str) … … static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) 468 537 SegmentContext *seg = s->priv_data; 469 538 AVFormatContext *oc = seg->avf; 470 539 AVStream *st = s->streams[pkt->stream_index]; 471 int64_t end_pts; 540 int64_t end_pts = INT64_MAX; 541 int start_frame = INT_MAX; 472 542 int ret; 473 543 474 544 if (seg->times) { 475 545 end_pts = seg->segment_count <= seg->nb_times ? 476 546 seg->times[seg->segment_count-1] : INT64_MAX; 547 } else if (seg->frames) { 548 start_frame = seg->segment_count <= seg->nb_frames ? 549 seg->frames[seg->segment_count-1] : INT_MAX; 477 550 } else { 478 551 end_pts = seg->time * seg->segment_count; 479 552 } 480 553 481 554 /* if the segment has video, start a new segment *only* with a key video frame */ 482 if ((st->codec->codec_type == AVMEDIA_TYPE_VIDEO || !seg->has_video) && 483 pkt->pts != AV_NOPTS_VALUE && 484 av_compare_ts(pkt->pts, st->time_base, 485 end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0 && 486 pkt->flags & AV_PKT_FLAG_KEY) { 555 if ((st->codec->codec_type == AVMEDIA_TYPE_VIDEO && seg->frame_count >= start_frame && pkt->flags & AV_PKT_FLAG_KEY) || 556 ((st->codec->codec_type == AVMEDIA_TYPE_VIDEO || !seg->has_video) && 557 pkt->pts != AV_NOPTS_VALUE && 558 av_compare_ts(pkt->pts, st->time_base, 559 end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0 && 560 pkt->flags & AV_PKT_FLAG_KEY)) { 487 561 ret = segment_end(s, seg->individual_header_trailer); 488 562 489 563 if (!ret) … … static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) 528 602 ret = ff_write_chained(oc, pkt->stream_index, pkt, s); 529 603 530 604 fail: 605 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) 606 seg->frame_count++; 607 531 608 if (ret < 0) { 532 609 if (seg->list) 533 610 avio_close(seg->list_pb); … … fail: 557 634 558 635 av_opt_free(seg); 559 636 av_freep(&seg->times); 637 av_freep(&seg->frames); 560 638 561 639 avformat_free_context(oc); 562 640 return ret; … … static const AVOption options[] = { 584 662 { "segment_time", "set segment duration", OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, 585 663 { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta_str), AV_OPT_TYPE_STRING, {.str = "0"}, 0, 0, E }, 586 664 { "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, 665 { "segment_frames", "set segment split frame numbers", OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, 587 666 { "segment_wrap", "set number after which the index wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, 588 667 { "segment_start_number", "set the sequence number of the first segment", OFFSET(segment_idx), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, 589 668
