ios - AVFoundation - Reverse an AVAsset and output video file -


i've seen question asked few times, none of them seem have working answers.

the requirement reverse , output video file (not play in reverse) keeping same compression, format, , frame rate source video.

ideally, solution able in memory or buffer , avoid generating frames image files (for ex: using avassetimagegenerator) , recompiling (resource intensive, unreliable timing results, changes in frame/image quality original, etc.).

--

my contribution: still not working, best i've tried far:

  • read in sample frames array of cmsamplebufferref[] using avassetreader.
  • write in reverse order using avassetwriter.
  • problem: seems timing each frame saved in cmsamplebufferref appending them backwards not work.
  • next, tried swapping timing information of each frame reverse/mirror frame.
  • problem: causes unknown error avassetwriter.
  • next step: i'm going avassetwriterinputpixelbufferadaptor

    - (avasset *)assetbyreversingasset:(avasset *)asset {     nsurl *tmpfileurl = [nsurl urlwithstring:@"/tmp/test.mp4"];         nserror *error;      // initialize avassetreader read input asset track     avassetreader *reader = [[avassetreader alloc] initwithasset:asset error:&error];     avassettrack *videotrack = [[asset trackswithmediatype:avmediatypevideo] lastobject];      avassetreadertrackoutput* readeroutput = [avassetreadertrackoutput assetreadertrackoutputwithtrack:videotrack outputsettings:nil];     [reader addoutput:readeroutput];     [reader startreading];      // read in samples array     nsmutablearray *samples = [[nsmutablearray alloc] init];      while(1) {         cmsamplebufferref sample = [readeroutput copynextsamplebuffer];          if (sample == null) {             break;         }          [samples addobject:(__bridge id)sample];         cfrelease(sample);     }      // initialize the writer save our temporary file.     cmformatdescriptionref formatdescription = cfbridgingretain([videotrack.formatdescriptions lastobject]);     avassetwriterinput *writerinput = [[avassetwriterinput alloc] initwithmediatype:avmediatypevideo outputsettings:nil sourceformathint:formatdescription];     cfrelease(formatdescription);      avassetwriter *writer = [[avassetwriter alloc] initwithurl:tmpfileurl                                                       filetype:avfiletypempeg4                                                          error:&error];     [writerinput setexpectsmediadatainrealtime:no];     [writer addinput:writerinput];     [writer startsessionatsourcetime:cmsamplebuffergetpresentationtimestamp((__bridge cmsamplebufferref)samples[0])];     [writer startwriting];       // traverse sample frames in reverse order     for(nsinteger = samples.count-1; >= 0; i--) {         cmsamplebufferref sample = (__bridge cmsamplebufferref)samples[i];          // since timing information built cmsamplebufferref          // need make copy of new timing info. copy         // timing data mirror frame @ samples[samples.count - -1]          cmitemcount numsampletimingentries;         cmsamplebuffergetsampletiminginfoarray((__bridge cmsamplebufferref)samples[samples.count - -1], 0, nil, &numsampletimingentries);         cmsampletiminginfo *timinginfo = malloc(sizeof(cmsampletiminginfo) * numsampletimingentries);         cmsamplebuffergetsampletiminginfoarray((__bridge cmsamplebufferref)sample, numsampletimingentries, timinginfo, &numsampletimingentries);          cmsamplebufferref samplewithcorrecttiming;         cmsamplebuffercreatecopywithnewtiming(                                               kcfallocatordefault,                                               sample,                                               numsampletimingentries,                                               timinginfo,                                               &samplewithcorrecttiming);          if (writerinput.readyformoremediadata)  {             [writerinput appendsamplebuffer:samplewithcorrecttiming];         }          cfrelease(samplewithcorrecttiming);         free(timinginfo);     }      [writer finishwriting];      return [avasset assetwithurl:tmpfileurl]; } 

worked on over last few days , able working.

source code here: http://www.andyhin.com/post/5/reverse-video-avfoundation

uses avassetreader read out samples/frames, extracts image/pixel buffer, , appends presentation time of mirror frame.


Comments

Popular posts from this blog

IF statement in MySQL trigger -

c++ - What does MSC in "// appease MSC" comments mean? -

javascript - Blogger related post gadget image Resize s72-c [ Need Expert Help ] -