mirror of
https://github.com/DevonCrawford/Video-Editing-Automation.git
synced 2026-01-10 06:28:02 -05:00
Random splice algorithm test!
This commit is contained in:
5
Makefile
5
Makefile
@@ -116,6 +116,11 @@ OBJS_BASE= VideoContext Clip ClipDecode OutputContext Timebase \
|
||||
$(DBE)test-sequence-encode: $$(call EXE_OBJS,$$@,$(OBJS_BASE))
|
||||
$(LINK_EXE)
|
||||
|
||||
OBJS_BASE=Sequence LinkedListAPI Clip Util VideoContext Timebase \
|
||||
OutputContext SequenceEncode SequenceDecode ClipDecode
|
||||
$(DBE)random-splice: $$(call EXE_OBJS,$$@,$(OBJS_BASE))
|
||||
$(LINK_EXE)
|
||||
|
||||
# $(1) = name of exe
|
||||
# $(2) = the list of basename object files that the executable needs to run, without .o
|
||||
define EXE_OBJS
|
||||
|
||||
349
examples/random-splice.c
Normal file
349
examples/random-splice.c
Normal file
@@ -0,0 +1,349 @@
|
||||
#include "RandomSplice.h"
|
||||
|
||||
/**
|
||||
* valgrind --leak-check=yes bin/examples/random-splice test-resources/sequence/out7.mov 30 48000 test-resources/sequence/ 300 80 40
|
||||
*/
|
||||
int main(int argc, char **argv) {
|
||||
if(argc < 8) {
|
||||
printf("usage: %s output_file fps sample_rate source_dir duration cut_len_avg cut_len_var\n", argv[0]);
|
||||
printf("\nExplanation\n------------\n");
|
||||
printf("output_file(string): output filename of encoded edit (ex. out.mov)\n");
|
||||
printf("fps(int): frames per second to use in sequence. All frame parameters are based on this (ex. 30 for 30fps)\n");
|
||||
printf("sample_rate(int): audio sample rate (ex. 48000 for 48kHz)\n");
|
||||
printf("source_dir(string): directory of raw video files that will be used in the edit\n");
|
||||
printf("duration(int): duration of output file (in frames - fps defined above)\n");
|
||||
printf("cut_len_avg(int): average length of cuts (in frames)\n");
|
||||
printf("cut_len_var(int): variability of average cuts used by the random number generator for max and min range\n");
|
||||
return -1;
|
||||
}
|
||||
RandSpliceParams par;
|
||||
strcpy(par.output_file, argv[1]);
|
||||
par.fps = atoi(argv[2]);
|
||||
par.sample_rate = atoi(argv[3]);
|
||||
strcpy(par.source_dir, argv[4]);
|
||||
par.duration = atoi(argv[5]);
|
||||
par.cut_len_avg = atoi(argv[6]);
|
||||
par.cut_len_var = atoi(argv[7]);
|
||||
par.pick_frames_recur = 0;
|
||||
|
||||
int num_files, ret = 0;
|
||||
char **files = get_filenames_in_dir(par.source_dir, &num_files);
|
||||
srand(time(NULL));
|
||||
|
||||
Sequence orig_seq, new_seq;
|
||||
init_sequence_cmp(&orig_seq, par.fps, par.sample_rate, &list_compare_clips_sequential);
|
||||
init_sequence_cmp(&new_seq, par.fps, par.sample_rate, &list_compare_clips_sequential);
|
||||
|
||||
ret = add_files(&orig_seq, files, num_files);
|
||||
if(ret < 0) {
|
||||
fprintf(stderr, "failed to add files\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *str = print_sequence(&orig_seq);
|
||||
printf("====== ORIG_SEQ =====\n%s\n", str);
|
||||
free(str);
|
||||
str = NULL;
|
||||
|
||||
ret = random_edit(&orig_seq, &new_seq, &par);
|
||||
if(ret < 0) {
|
||||
fprintf(stderr, "random_edit() error: Failed to finish edit\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
str = print_sequence(&new_seq);
|
||||
printf("====== NEW_SEQ =====\n%s\n", str);
|
||||
free(str);
|
||||
str = NULL;
|
||||
|
||||
if(new_seq.clips.head != NULL) {
|
||||
// output parameters
|
||||
OutputParameters op;
|
||||
VideoOutParams vp;
|
||||
AudioOutParams ap;
|
||||
Clip *clip1 = (Clip *) (new_seq.clips.head->data);
|
||||
set_video_out_params(&vp, clip1->vid_ctx->video_codec_ctx);
|
||||
vp.codec_id = AV_CODEC_ID_NONE;
|
||||
vp.bit_rate = -1;
|
||||
set_audio_out_params(&ap, clip1->vid_ctx->audio_codec_ctx);
|
||||
if(set_output_params(&op, par.output_file, vp, ap) < 0) {
|
||||
fprintf(stderr, "Failed to set output params\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = write_sequence(&new_seq, &op);
|
||||
if(ret < 0) {
|
||||
fprintf(stderr, "Failed to write new sequence to output file[%s]\n", op.filename);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
// print_str_arr(files, num_files);
|
||||
free_str_arr(&files, num_files);
|
||||
free_sequence(&orig_seq);
|
||||
free_sequence(&new_seq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a random edit. This function calls itself recursively to continue making
|
||||
* cuts until the output sequence is our desired length
|
||||
* @param os original sequence (input)
|
||||
* @param ns new sequence (output)
|
||||
* @param par parameters from user to control algorithm
|
||||
* @return 0 on success (fully edited sequence), < 0 on fail
|
||||
*/
|
||||
int random_edit(Sequence *os, Sequence *ns, RandSpliceParams *par) {
|
||||
if(par->cut_len_var > par->cut_len_avg) {
|
||||
fprintf(stderr, "random_edit() error: cut_len_var[%d] must be less than cut_len_avg[%d]\n", par->cut_len_var, par->cut_len_avg);
|
||||
return -1;
|
||||
}
|
||||
if(get_sequence_duration(ns) > par->duration) {
|
||||
return 0;
|
||||
}
|
||||
int ret = random_cut(os, ns, par);
|
||||
if(ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return random_edit(os, ns, par);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a random cut from original sequence and place that clip into new sequence
|
||||
* @param os original sequence (input)
|
||||
* @param ns new sequence (output)
|
||||
* @param par parameters from user to control algorithm
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int random_cut(Sequence *os, Sequence *ns, RandSpliceParams *par) {
|
||||
int s, e;
|
||||
int ret = pick_frames(os, par, &s, &e);
|
||||
if(ret < 0) {
|
||||
fprintf(stderr, "random_cut() error: Failed to pick frames\n");
|
||||
return ret;
|
||||
}
|
||||
return cut_remove_insert(os, ns, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut a clip out of original sequence and insert it into new sequence in sorted order
|
||||
* @param os Original sequence
|
||||
* @param ns New Sequence
|
||||
* @param start_index start frame of cut in original sequence
|
||||
* @param end_index end frame of cut in original sequence
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int cut_remove_insert(Sequence *os, Sequence *ns, int start_index, int end_index) {
|
||||
int cut_center_index = start_index + ((end_index - start_index) / 2);
|
||||
int ret = cut_clip(os, start_index);
|
||||
if(ret < 0) {
|
||||
fprintf(stderr, "cut_remove_insert() error: Failed to cut clip at start index[%d]\n", start_index);
|
||||
return ret;
|
||||
}
|
||||
ret = cut_clip(os, end_index);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "cut_remove_insert() error: Failed to cut clip at end index[%d]\n", end_index);
|
||||
return ret;
|
||||
}
|
||||
Clip *cut = NULL;
|
||||
find_clip_at_index(os, cut_center_index, &cut);
|
||||
if(!cut) {
|
||||
fprintf(stderr, "cut_remove_insert() error: Failed to find clip at cut center index[%d]\n", cut_center_index);
|
||||
return -1;
|
||||
}
|
||||
Clip *cut_copy = alloc_clip(cut->url);
|
||||
if(cut_copy == NULL) {
|
||||
fprintf(stderr, "cut_remove_insert() error: Failed to allocate cut_copy\n");
|
||||
return -1;
|
||||
}
|
||||
ret = set_clip_bounds_pts(cut_copy, cut->orig_start_pts, cut->orig_end_pts);
|
||||
if(ret < 0) {
|
||||
free_clip(cut_copy);
|
||||
free(cut_copy);
|
||||
cut_copy = NULL;
|
||||
fprintf(stderr, "cut_remove_insert() error: Failed to set clip bounds on cut copy\n");
|
||||
return ret;
|
||||
}
|
||||
ret = sequence_insert_clip_sorted(ns, cut_copy);
|
||||
if(ret < 0) {
|
||||
free_clip(cut_copy);
|
||||
free(cut_copy);
|
||||
cut_copy = NULL;
|
||||
fprintf(stderr, "cut_remove_insert() error: failed to add clip[%s] to new sequence\n", cut_copy->url);
|
||||
return ret;
|
||||
}
|
||||
ret = sequence_ripple_delete_clip(os, cut);
|
||||
if(ret < 0) {
|
||||
free_clip(cut_copy);
|
||||
free(cut_copy);
|
||||
cut_copy = NULL;
|
||||
fprintf(stderr, "cut_remove_insert() error: Failed to delete clip from original sequence\n");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly pick start and end frames given user parameters
|
||||
* @param seq Original sequence to pick frames
|
||||
* @param par user parameters
|
||||
* @param start_index output index of start frame for cut
|
||||
* @param end_index output index of end frame for cut
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int pick_frames(Sequence *seq, RandSpliceParams *par, int *start_index, int *end_index) {
|
||||
if(par->pick_frames_recur > PICK_FRAMES_RECUR_LIMIT) {
|
||||
fprintf(stderr, "pick_frames() error: par->pick_frames_recur[%d] > limit[%d]\nThis should never happen\n", par->pick_frames_recur, PICK_FRAMES_RECUR_LIMIT);
|
||||
return -1;
|
||||
}
|
||||
int64_t seq_dur = get_sequence_duration(seq);
|
||||
if(seq_dur <= 0) {
|
||||
fprintf(stderr, "pick_frames() error: sequence duration[%ld] is invalid\n", seq_dur);
|
||||
return -1;
|
||||
}
|
||||
int s = rand_range(0, seq_dur - par->cut_len_avg - 1);
|
||||
int e_var = rand_range((-1)*(par->cut_len_var), par->cut_len_var);
|
||||
int e = s + par->cut_len_avg + e_var;
|
||||
if(e > seq_dur) {
|
||||
e = seq_dur;
|
||||
}
|
||||
Clip *sc = NULL, *se = NULL;
|
||||
find_clip_at_index(seq, s, &sc);
|
||||
find_clip_at_index(seq, e, &se);
|
||||
if(!sc || !se) {
|
||||
fprintf(stderr, "pick_frames() error: clip does not exist at start[%d] or end[%d] index\n", s, e);
|
||||
return -1;
|
||||
}
|
||||
// If start and end index do not lie on the same clip.. try again
|
||||
if(compare_clips_sequential(sc, se) != 0) {
|
||||
++(par->pick_frames_recur);
|
||||
return pick_frames(seq, par, start_index, end_index);
|
||||
}
|
||||
*start_index = s;
|
||||
*end_index = e;
|
||||
par->pick_frames_recur = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate random number between range in the uniform distribution
|
||||
* @param min low bound (inclusive)
|
||||
* @param max high bound (inclusive)
|
||||
* @return random number between min and max on a uniform distribution
|
||||
*/
|
||||
int rand_range(int min, int max) {
|
||||
int diff = max-min;
|
||||
return (int) (((double)(diff+1)/RAND_MAX) * rand() + min);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all files from string array into sequence!
|
||||
* @param seq Sequence
|
||||
* @param files string array of filenames (videos to be added)
|
||||
* @param num_files number strings in files array
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int add_files(Sequence *seq, char **files, int num_files) {
|
||||
int ret;
|
||||
for(int i = 0; i < num_files; i++) {
|
||||
Clip *curr = alloc_clip(files[i]);
|
||||
if(curr == NULL) {
|
||||
printf("add_files() warning: failed to allocate clip[%s]\n", files[i]);
|
||||
}
|
||||
ret = sequence_insert_clip_sorted(seq, curr);
|
||||
if(ret < 0) {
|
||||
fprintf(stderr, "add_files() error: failed to add clip[%s] to sequence\n", files[i]);
|
||||
return ret;
|
||||
}
|
||||
printf("added clip[%s] to original sequence\n", files[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* print string array
|
||||
* @param str string array
|
||||
* @param rows number of strings
|
||||
*/
|
||||
void print_str_arr(char **str, int rows) {
|
||||
for (int i = 0; i < rows; i++) {
|
||||
printf("%s\n", str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free array of strings
|
||||
* @param str pointer to array of strings
|
||||
* @param rows number of strings in array
|
||||
*/
|
||||
void free_str_arr(char ***str, int rows) {
|
||||
char **s = *str;
|
||||
if(s != NULL) {
|
||||
for(int i = 0; i < rows; i++) {
|
||||
free(s[i]);
|
||||
s[i] = NULL;
|
||||
}
|
||||
free(*str);
|
||||
*str = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all filenames in directory
|
||||
* @param name of directory to search
|
||||
* @param rows number of files
|
||||
* @return array of strings (filenames)
|
||||
*/
|
||||
char **get_filenames_in_dir(char *dirname, int *rows) {
|
||||
char buf[4096];
|
||||
buf[0] = 0;
|
||||
*rows = 0;
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
if ((dir = opendir (dirname)) != NULL) {
|
||||
/* print all the files and directories within directory */
|
||||
while ((ent = readdir (dir)) != NULL) {
|
||||
strcat(buf, dirname);
|
||||
strcat(buf, ent->d_name);
|
||||
if(!is_regular_file(buf)) {
|
||||
buf[0] = 0;
|
||||
continue;
|
||||
}
|
||||
buf[0] = 0;
|
||||
++(*rows);
|
||||
}
|
||||
} else {
|
||||
perror ("");
|
||||
return NULL;
|
||||
}
|
||||
rewinddir(dir);
|
||||
|
||||
char **str = malloc(sizeof(char *) * (*rows));
|
||||
|
||||
/* print all the files and directories within directory */
|
||||
int i = 0;
|
||||
while ((ent = readdir (dir)) != NULL) {
|
||||
strcat(buf, dirname);
|
||||
strcat(buf, ent->d_name);
|
||||
if(!is_regular_file(buf)) {
|
||||
buf[0] = 0;
|
||||
continue;
|
||||
}
|
||||
str[i] = malloc(sizeof(char) * (strlen(buf) + 1));
|
||||
strcpy(str[i++], buf);
|
||||
buf[0] = 0;
|
||||
}
|
||||
closedir (dir);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if path is file or directory
|
||||
* @param path filename
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int is_regular_file(const char *path) {
|
||||
struct stat path_stat;
|
||||
stat(path, &path_stat);
|
||||
return S_ISREG(path_stat.st_mode);
|
||||
}
|
||||
@@ -88,7 +88,9 @@ typedef struct Clip {
|
||||
} Clip;
|
||||
|
||||
/**
|
||||
* Allocate clip on heap and initialize to default values
|
||||
* Allocate clip on heap, initialize default values and open the clip.
|
||||
* It is important to open the clip when first created so we can set default
|
||||
* values such as clip->orig_end_pts by reading file contents (length of video)
|
||||
* @param url filename
|
||||
* @return NULL on error, not NULL on success
|
||||
*/
|
||||
|
||||
@@ -111,7 +111,16 @@ as a pointer to the first and last element of the list.
|
||||
**/
|
||||
void insertSorted(List* list, void* toBeAdded);
|
||||
|
||||
|
||||
/** Uses the comparison function pointer to place the element in the
|
||||
* appropriate position in the list. Also return the node of inserted element
|
||||
* should be used as the only insert function if a sorted list is required.
|
||||
*@pre List exists and has memory allocated to it. Node to be added is valid.
|
||||
*@post The node to be added will be placed immediately before or after the first occurrence of a related node
|
||||
*@param list a pointer to the dummy head of the list containing function pointers for delete and compare, as well
|
||||
as a pointer to the first and last element of the list.
|
||||
*@param toBeAdded a pointer to data that is to be added to the linked list
|
||||
**/
|
||||
Node *insertSortedGetNode(List *list, void *toBeAdded);
|
||||
|
||||
/** Removes data from from the list, deletes the node and frees the memory,
|
||||
* changes pointer values of surrounding nodes to maintain list structure.
|
||||
|
||||
137
include/RandomSplice.h
Normal file
137
include/RandomSplice.h
Normal file
@@ -0,0 +1,137 @@
|
||||
#ifndef _RANDOM_SPLICE_
|
||||
#define _RANDOM_SPLICE_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "OutputContext.h"
|
||||
|
||||
#define PICK_FRAMES_RECUR_LIMIT 50
|
||||
|
||||
typedef struct RandSpliceParams {
|
||||
|
||||
/*************** SEQUENCE PARAMS ***************/
|
||||
/*
|
||||
output filename
|
||||
*/
|
||||
char output_file[1024];
|
||||
/*
|
||||
frames per second to use in sequence
|
||||
*/
|
||||
int fps;
|
||||
/*
|
||||
audio sample rate
|
||||
*/
|
||||
int sample_rate;
|
||||
|
||||
/*************** ALGORITHM PARAMS ***************/
|
||||
/*
|
||||
directory to fetch video files
|
||||
*/
|
||||
char source_dir[1024];
|
||||
/*
|
||||
duration of output video (in frames)
|
||||
*/
|
||||
int duration;
|
||||
/*
|
||||
average length of cuts (in frames)
|
||||
*/
|
||||
int cut_len_avg;
|
||||
/*
|
||||
variability of average cuts
|
||||
*/
|
||||
int cut_len_var;
|
||||
|
||||
/*************** INTERNAL ONLY ***************/
|
||||
int pick_frames_recur;
|
||||
} RandSpliceParams;
|
||||
|
||||
/**
|
||||
* Make a random edit. This function calls itself recursively to continue making
|
||||
* cuts until the output sequence is our desired length
|
||||
* @param os original sequence (input)
|
||||
* @param ns new sequence (output)
|
||||
* @param par parameters from user to control algorithm
|
||||
* @return 0 on success (fully edited sequence), < 0 on fail
|
||||
*/
|
||||
int random_edit(Sequence *os, Sequence *ns, RandSpliceParams *par);
|
||||
|
||||
/**
|
||||
* Make a random cut from original sequence and place that clip into new sequence
|
||||
* @param os original sequence (input)
|
||||
* @param ns new sequence (output)
|
||||
* @param par parameters from user to control algorithm
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int random_cut(Sequence *os, Sequence *ns, RandSpliceParams *par);
|
||||
|
||||
/**
|
||||
* Cut a clip out of original sequence and insert it into new sequence in sorted order
|
||||
* @param os Original sequence
|
||||
* @param ns New Sequence
|
||||
* @param start_index start frame of cut in original sequence
|
||||
* @param end_index end frame of cut in original sequence
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int cut_remove_insert(Sequence *os, Sequence *ns, int start_index, int end_index);
|
||||
|
||||
/**
|
||||
* Randomly pick start and end frames given user parameters
|
||||
* @param seq Original sequence to pick frames
|
||||
* @param par user parameters
|
||||
* @param start_index output index of start frame for cut
|
||||
* @param end_index output index of end frame for cut
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int pick_frames(Sequence *seq, RandSpliceParams *par, int *start_index, int *end_index);
|
||||
|
||||
/**
|
||||
* Generate random number between range in the uniform distribution
|
||||
* @param min low bound (inclusive)
|
||||
* @param max high bound (inclusive)
|
||||
* @return random number between min and max on a uniform distribution
|
||||
*/
|
||||
int rand_range(int min, int max);
|
||||
|
||||
/**
|
||||
* Add all files from string array into sequence!
|
||||
* @param seq Sequence
|
||||
* @param files string array of filenames (videos to be added)
|
||||
* @param num_files number strings in files array
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int add_files(Sequence *seq, char **files, int num_files);
|
||||
|
||||
/**
|
||||
* print string array
|
||||
* @param str string array
|
||||
* @param rows number of strings
|
||||
*/
|
||||
void print_str_arr(char **str, int rows);
|
||||
|
||||
/**
|
||||
* Free array of strings
|
||||
* @param str pointer to array of strings
|
||||
* @param rows number of strings in array
|
||||
*/
|
||||
void free_str_arr(char ***str, int rows);
|
||||
|
||||
/**
|
||||
* Get all filenames in directory
|
||||
* @param name of directory to search
|
||||
* @param rows number of files
|
||||
* @return array of strings (filenames)
|
||||
*/
|
||||
char **get_filenames_in_dir(char *dirname, int *rows);
|
||||
|
||||
/**
|
||||
* Tests if path is file or directory
|
||||
* @param path filename
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int is_regular_file(const char *path);
|
||||
|
||||
#endif
|
||||
@@ -64,6 +64,16 @@ typedef struct Sequence {
|
||||
*/
|
||||
int init_sequence(Sequence *seq, double fps, int sample_rate);
|
||||
|
||||
/**
|
||||
* Initialize a new sequence, list of clips along with a custom compare function (for insertSorted)
|
||||
* @param seq Sequence to initialize
|
||||
* @param fps frames per second
|
||||
* @param sample_rate sample_rate of the audio stream
|
||||
* @param compareFunc custom compare function used in sorting and searching
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int init_sequence_cmp(Sequence *seq, double fps, int sample_rate, int (*compareFunc)(const void* first,const void* second));
|
||||
|
||||
/**
|
||||
* Get duration of sequence in frames (defined by fps)
|
||||
* @param seq Sequence
|
||||
@@ -103,6 +113,25 @@ void sequence_add_clip_pts(Sequence *seq, Clip *clip, int64_t start_pts);
|
||||
*/
|
||||
void sequence_append_clip(Sequence *seq, Clip *clip);
|
||||
|
||||
/**
|
||||
* Insert clip sorted by:
|
||||
* 1. Date & time of file
|
||||
* 2. clip->orig_start_pts
|
||||
* This function will generate the sequence pts for the clip (clip->start_pts and clip->end_pts)
|
||||
* @param seq Sequence
|
||||
* @param clip Clip to insert
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int sequence_insert_clip_sorted(Sequence *seq, Clip *clip);
|
||||
|
||||
/**
|
||||
* Shift clips sequence pts to after the current node (insert clip function)
|
||||
* @param seq Sequence
|
||||
* @param curr_node current clip which should shift all following nodes
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int shift_clips_after(Sequence *seq, Node *curr_node);
|
||||
|
||||
/**
|
||||
* Delete a clip from a sequence and move all following clips forward
|
||||
* @param seq Sequence
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
#include "Clip.h"
|
||||
|
||||
/**
|
||||
* Allocate clip on heap and initialize to default values
|
||||
* Allocate clip on heap, initialize default values and open the clip.
|
||||
* It is important to open the clip when first created so we can set default
|
||||
* values such as clip->orig_end_pts by reading file contents (length of video)
|
||||
* @param url filename
|
||||
* @return NULL on error, not NULL on success
|
||||
*/
|
||||
Clip *alloc_clip(char *url) {
|
||||
Clip *clip = malloc(sizeof(struct Clip));
|
||||
if(clip == NULL || init_clip(clip, url) < 0) {
|
||||
if(clip == NULL || init_clip(clip, url) < 0 || open_clip(clip) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return clip;
|
||||
@@ -410,7 +412,6 @@ int64_t compare_clips_sequential(Clip *f, Clip *s) {
|
||||
return -2;
|
||||
}
|
||||
double diff = difftime(f->file_stats.st_mtime, s->file_stats.st_mtime);
|
||||
printf("difftime: %f\n", diff);
|
||||
if(diff < 0.01 && diff > -0.01) {
|
||||
// if equal date & time
|
||||
// compare start pts
|
||||
|
||||
@@ -176,6 +176,52 @@ void insertSorted(List *list, void *toBeAdded){
|
||||
return;
|
||||
}
|
||||
|
||||
/** Uses the comparison function pointer to place the element in the
|
||||
* appropriate position in the list. Also return the node of inserted element
|
||||
* should be used as the only insert function if a sorted list is required.
|
||||
*@pre List exists and has memory allocated to it. Node to be added is valid.
|
||||
*@post The node to be added will be placed immediately before or after the first occurrence of a related node
|
||||
*@param list a pointer to the dummy head of the list containing function pointers for delete and compare, as well
|
||||
as a pointer to the first and last element of the list.
|
||||
*@param toBeAdded a pointer to data that is to be added to the linked list
|
||||
**/
|
||||
Node *insertSortedGetNode(List *list, void *toBeAdded){
|
||||
if (list == NULL || toBeAdded == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (list->head == NULL){
|
||||
insertBack(list, toBeAdded);
|
||||
return list->head;
|
||||
}
|
||||
|
||||
if (list->compare(toBeAdded, list->head->data) <= 0){
|
||||
insertFront(list, toBeAdded);
|
||||
return list->head;
|
||||
}
|
||||
|
||||
if (list->compare(toBeAdded, list->tail->data) > 0){
|
||||
insertBack(list, toBeAdded);
|
||||
return list->tail;
|
||||
}
|
||||
|
||||
Node* currNode = list->head;
|
||||
|
||||
while (currNode != NULL){
|
||||
if (list->compare(toBeAdded, currNode->data) <= 0){
|
||||
Node* newNode = initializeNode(toBeAdded);
|
||||
newNode->next = currNode;
|
||||
newNode->previous = currNode->previous;
|
||||
currNode->previous->next = newNode;
|
||||
currNode->previous = newNode;
|
||||
(list->length)++;
|
||||
return newNode;
|
||||
}
|
||||
currNode = currNode->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* deleteDataFromList(List* list, void* toBeDeleted){
|
||||
if (list == NULL || toBeDeleted == NULL){
|
||||
return NULL;
|
||||
|
||||
@@ -18,11 +18,23 @@
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int init_sequence(Sequence *seq, double fps, int sample_rate) {
|
||||
if(seq == NULL) {
|
||||
fprintf(stderr, "sequence is NULL, cannot initialize");
|
||||
return init_sequence_cmp(seq, fps, sample_rate, &list_compare_clips);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a new sequence, list of clips along with a custom compare function (for insertSorted)
|
||||
* @param seq Sequence to initialize
|
||||
* @param fps frames per second
|
||||
* @param sample_rate sample_rate of the audio stream
|
||||
* @param compareFunc custom compare function used in sorting and searching
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int init_sequence_cmp(Sequence *seq, double fps, int sample_rate, int (*compareFunc)(const void* first,const void* second)) {
|
||||
if(seq == NULL || compareFunc == NULL) {
|
||||
fprintf(stderr, "init_sequence_cmp() error: params cannot be NULL\n");
|
||||
return -1;
|
||||
}
|
||||
seq->clips = initializeList(&list_print_clip, &list_delete_clip, &list_compare_clips);
|
||||
seq->clips = initializeList(&list_print_clip, &list_delete_clip, compareFunc);
|
||||
seq->clips_iter = createIterator(seq->clips);
|
||||
seq->video_time_base = (AVRational){1, fps * SEQ_VIDEO_FRAME_DURATION};
|
||||
seq->audio_time_base = (AVRational){1, sample_rate};
|
||||
@@ -115,6 +127,57 @@ void sequence_append_clip(Sequence *seq, Clip *clip) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert clip sorted by:
|
||||
* 1. Date & time of file
|
||||
* 2. clip->orig_start_pts
|
||||
* This function will generate the sequence pts for the clip (clip->start_pts and clip->end_pts)
|
||||
* @param seq Sequence
|
||||
* @param clip Clip to insert
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int sequence_insert_clip_sorted(Sequence *seq, Clip *clip) {
|
||||
if(seq == NULL || clip == NULL) {
|
||||
fprintf(stderr, "sequence_insert_clip_sorted() error: parameters cannot be NULL\n");
|
||||
return -1;
|
||||
}
|
||||
Node *node = insertSortedGetNode(&(seq->clips), clip);
|
||||
if(node == NULL) {
|
||||
fprintf(stderr, "sequence_insert_clip_sorted() error: could not insert clip in sorted order\n");
|
||||
return -1;
|
||||
}
|
||||
seq->clips_iter.current = seq->clips.head;
|
||||
if(node->previous == NULL) {
|
||||
move_clip_pts(seq, clip, 0);
|
||||
} else {
|
||||
move_clip_pts(seq, clip, ((Clip *) (node->previous->data))->end_pts);
|
||||
}
|
||||
return shift_clips_after(seq, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift clips sequence pts to after the current node (insert clip function)
|
||||
* @param seq Sequence
|
||||
* @param curr_node current clip which should shift all following nodes
|
||||
* @return >= 0 on success
|
||||
*/
|
||||
int shift_clips_after(Sequence *seq, Node *curr_node) {
|
||||
if(seq == NULL || curr_node == NULL) {
|
||||
fprintf(stderr, "shift_clips_after() error: parameters cannot be NULL\n");
|
||||
return -1;
|
||||
}
|
||||
Clip *curr = (Clip *) (curr_node->data);
|
||||
int64_t shift = curr->end_pts - curr->start_pts;
|
||||
Node *node = curr_node->next;
|
||||
while(node != NULL) {
|
||||
Clip *next = (Clip *) (node->data);
|
||||
next->start_pts += shift;
|
||||
next->end_pts += shift;
|
||||
node = node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a clip from a sequence and move all following clips forward
|
||||
* @param seq Sequence
|
||||
|
||||
Reference in New Issue
Block a user