15

I generate video by using AVFoundation. After that I write video to the Photos library by using Photos Framework (and get instance of PHAsset after that).

I want to set custom thumbnail for added PHAsset (last frame from the video), but can't find a solution. How I can attach custom thumbnail for added video? I want to see my custom thumbnail in Photos application, when I'm opening in.

Also, I know how to get some image from the video by using AVAssetImageGenerator, but I want to see my thumbnail in Photo application.

VC.One
  • 14,790
  • 4
  • 25
  • 57
Andrew Romanov
  • 4,774
  • 3
  • 25
  • 40
  • Please post your work-in-progress implementation. – JAL Sep 12 '16 at 22:38
  • Sorry, what kind of the work-in-progress I can show? I have no problems with video generation. Now I have mp4 video in a file and don't know how to set a custom thumbnail image for the video. To video generation I use code from https://github.com/sakrist/ClipMaker/blob/master/ClipMaker/VBPhotoToVideo.m, method - (void) writeImagesAsMovie:(NSArray *)array toPath:(NSString*)path fps:(int)fps progressBlock:(void(^)(float progress))block. the code is too long for posting it here. – Andrew Romanov Sep 13 '16 at 03:38
  • I can't find methods or may be properties that I can use to add a thumbnail, therefore I haven't a code that tries to add a thumbnail to the video. – Andrew Romanov Sep 13 '16 at 03:57
  • @HadiHassan, calm down buddy nobody cares about virtual numbers on some internetz website. I'll tell you what happened to me... 2-hours ago I downvoted your answer since it did not add any new/useful knowledge. It just repeats a variation of @ Mick's Answer as posted since yesterday. 10 mins later you downvoted both my answer & Question. **I didn't say anything**. About 30 mins ago my Answer got new upvote again, 1-min later it got a downvote, what's going on? Downvoted 3 times now & "punished" for being Question editor? I can only laugh at such "seriousness"... – VC.One Sep 18 '16 at 16:09
  • @HadiHassan, wow it seems you are under attack. Infact both of us. I did not know you also got 3 downvotes. I agree its suspicious voting. Don't worry the site has automatic reversal script of unfair downvotes (see our reps are back to almost normal). – VC.One Sep 18 '16 at 16:20
  • whoever is down voted the answer of @Hadi Hassan, asked him for clarification of his answer before doing such. They needed clarification because they are running with same problem with the topic. But when they found that an inappropriate answer is serially up voted just purposely, and there is an answer which deserve to be correct is down voted by the person who is not willing to understand the problem of the question, no way out there. This site is built to help developers, not to divert people in a wrong direction. – Mahesh Agrawal Sep 18 '16 at 16:27
  • dear @M.K. I am here for helping and to get help, I deleted my answer, and thumbs up for you and others – Monah Sep 18 '16 at 16:36
  • @Hadi Hassan no one want you to delete your answer, we need solution, if you can provide some light towards the solution, just point us, you literally ignored the request of the needed ones. everyone here is to help others. chilled up man.. – Mahesh Agrawal Sep 18 '16 at 16:40

2 Answers2

11

To add a custom thumbnail to your MP4:

METHOD 1: using AVMutableMetadataItem...

See if the code in this Question helps you.

AVMutableMetadataItem *item = [[AVMutableMetadataItem alloc] init];
item.keySpace = AVMetadataKeySpaceCommon;
item.key = AVMetadataCommonKeyArtwork;
item.value = UIImageJPEGRepresentation([[UIImage alloc] initWithContentsOfFile:[[NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@".image"]]);

[newMetadataArray addObject:item];
assetWrtr.metadata = newMetadataArray;

[assetWrtr startWriting];
[assetWrtr startSessionAtSourceTime:kCMTimeZero];

See also this Apple forum Post. Read the whole thread for context of code & usage.

METHOD 2: manually writing bytes...

Short version :

Find the following atoms (tags)... moov goes to udta goes to meta then ilst and here, simply add a covr atom (24 bytes) followed by the bytes of your jpeg image (bytes FF D8 up to FF D9). Update the size entries (32-bit integers) for moov, udta, ilst and covr to reflect the newly added bytes). That's it. Finished.

Expanded version :

( note / recommended ):
• Ideally check a test MP4 in a hex editor (d/load a free one) to follow the bytes as described below.

Read : Apple's Quicktime Format specs and Cimmaron System's MP4 atoms guide.

1) Find moov bytes...

(when viewed in a hex editor) Your MP4 bytes should look something like this.

00 00 00 20 66 74 79 70 69 73 6F 6D 00 00 02 00     ... ftypisom....
69 73 6F 6D 69 73 6F 32 61 76 63 31 6D 70 34 31     isomiso2avc1mp41
00 00 00 08 66 72 65 65 00 00 99 70 6D 64 61 74     ....free..™pmdat

These are the opening bytes and the important part is that is has the bytes 6D 64 61 74 meaning mdat (as ASCII characters, on right side of shown bytes view). I don't use iOS so I hope it makes mdat first & then moov is placed towards end of file, in such a case it's easy to add extra bytes without corrupting the file. If you see mdat within first 64 bytes of your file then you can proceed with my advice below.

edit: (if not already like this by default) It seems you can place mdat atom at front of file (first 64 bytes) if your exportSession settings have :

exportSession.shouldOptimizeForNetworkUse = NO; 

To find moov, read the previous 4 bytes (as one integer) before the ASCII letters "mdat". In above example, this is a 4-byte integer of 00 00 99 70 ( = 39280 bytes). This means skip a total of 39280 + 8 bytes starting from 6D.. 64.. 61 and so on. Once skipped, the next 4 bytes should be 6D 6F 6F 76 ("moov" in ASCII). Note this offset/position as moov beginning.

2) Add covr bytes...

From moov beginning, read the following bytes searching for :

  • find entry udta as bytes 75 64 74 61. Note for later reference : this position - 4 as starting of udta size pos.
  • find entry meta as bytes 6D 65 74 61.
  • find entry ilst as bytes 69 6C 73 74. Note for later reference : this position - 4 as starting of ilst size pos.

note: If any of the above entries is not found, you must create those bytes. Check page 14 onwards of this atoms guide to know which bytes (values) are needed for those above atoms.

  • at the ending of ilst add four zero bytes 00 00 00 00 (later this will be updated as total covr size). For reference, note these 4 bytes' position as covr size pos.
  • add entry covr by writing bytes/integer as 63 6F 76 72.
  • add bytes 00 00 ED EA 64 61 74 61 00 00 00 0D 00 00 00 00 then it's ready for JPEG image bytes.

3) Add JPEG bytes...

Paste the bytes of JPEG image. These bytes begin with FF D8 and end with FF D9. Note the total amount of these bytes as jpeg size.

4) Update sizes...

  • for covr : go to the starting of covr size pos, replace the four 00 00 00 00 bytes with hex result of jpeg size + 20 calculation.
  • for ilst : go to the starting of ilst size pos bytes, replace those four bytes with hex result of current ilst size + covr size + 4 calculation..
  • for udta : go to the starting of udta size pos bytes, replace those four bytes with hex result of current udta size + covr size + 4 calculation..

conclusion

Test MP4 file by enabling some thumbnail view in your program/tool. You should see the jpg now used as icon for the edited mp4 file.

PS: I don't code for iOS (no Swift or Objective-C knowledge) so I can't show you an example code, only advice on creating the bytes. This task can even be done manually using a hex editor. The main thing for you as an iOS coder is to be able to write bytes to an existing file and re-save as new filename (or do overwrites when code is perfected).

Community
  • 1
  • 1
VC.One
  • 14,790
  • 4
  • 25
  • 57
  • 3
    if anyone will understand this answer and can program the video file to change required bytes from the video file in objective-c or swift, its possible to change the thumbnail image from the video file's metadata. – Mahesh Agrawal Sep 18 '16 at 13:45
  • 1
    @M.K.... all I know is the custom thumbnail must be put into a `covr` atom which is a child of the larger `moov` atom and its child atoms (hence the constant searching for specific bytes to edit). Is there an `AVFoundation` style library or API that allows adding custom metadata to an mp4? Maybe an iOS port of `FFmpeg` can do it? – VC.One Sep 18 '16 at 15:38
  • i did not studied that deep in bytes programming but i can tell you that we can edit the bytes data like you said using tags. i mean its possible using AVFoundation. I am trying to find some solution. – Mahesh Agrawal Sep 18 '16 at 15:42
  • 1
    @M.K. Does this [**Question**'s code](http://stackoverflow.com/q/14392252/2057709) help with ideas? Anyways from research I found [**AVMutableMetadataItem**](https://developer.apple.com/reference/avfoundation/avmutablemetadataitem). This allows editing metadata during `avassetexportsession`. Most of the shown vars are not neccesary for embedding artwork but you would need `var value:` and `var dataType:` to be defined. **Value** is `covr` but **dataType** is more mysterious. Should be something like `binary` or such but I can't find a list of the exact wording required. – VC.One Sep 18 '16 at 19:18
  • 1
    i think its the solution is in the question you pointed. its already editing the artwork. i think its the code to change thumbnail. the question you pointed its problem with saving but rest of code must be working. you should edit your answer and post the link to the question. We have not setup prework code to test but the Asker can test it. – Mahesh Agrawal Sep 18 '16 at 19:23
1

If you are writing a part of the app which will browse the photo library and display the thumbnails, then you should be able to do this as follows:

  1. get the PHAsset
  2. from the PHAsset request an AVasset using requestAVAssetForVideo
  3. generate a thumbnail at the time you require using AVAssetImageGenerator and the copyCGImageAtTime method

One thing to be wary of is that timing and selecting a specific frame in videos is a tricky science/art - getting exactly the frame you want from a time might prove difficult.

Also, the video will have to be decoded at least partially to get the image - the above approach is meant to leverage the frameworks to do this efficiently, but even efficient video decoding is time and power hungry.

If you are saying you want the videos to appear in the standard 'Photos' app on iOS with a custom thumbnail you assign to them, then I'm not sure how you can do that.

Mick
  • 24,231
  • 1
  • 54
  • 120