Videos shared to Facebook and images/thumbnails generated with ffmpeg

If you share a video on Facebook, the thumbnail image of the video does not come directly from the website that is hosting the video itself. Facebook uses a wrapper script called safe_image.php to serve images from external webservers. The same is true if you share the link of an image. The problem is that this wrapper script does not accept all JPEG files, but only ones that have a JFIF header.

Let's see an example. If you share a YouTube video by specifying the URL in the Facebook Share dialog (eg. http://www.youtube.com/watch?v=wM45Gl_e4Jo), then Facebook downloads the contents of the given URL, analizes it and in case of YouTube it determines that this page contains an embedded video that you want to share. Facebook finds the URL to the video's thumbnail image (eg. http://i.ytimg.com/vi/wM45Gl_e4Jo/2.jpg) and embeds this image in your Facebook feed with the safe_image.php wrapper script (eg. http://external.ak.fbcdn.net/safe_image.php?d=f4e1a456e4276f3db1597e1b0e82f90f&w=130&h=130&url=http%3A%2F%2Fi.ytimg.com%2Fvi%2FwM45Gl_e4Jo%2F2.jpg).

To make this work with ffmpeg generated (thumbnail) images, you've to apply some sort of a fix. The jpegtran utility is perfect for the job, because it writes JPEG images only with a JFIF marker in the header and it does not recompress the image (thus image quality is preserved). The following command creates "fixed" JPEG files from your input image:
jpegtran -outfile fixed_image.jpg input.jpg
You can add the -optimize option too and it'll make the result slightly smaller than the input.

On Debian/Ubuntu you can find jpegtran in the libjpeg-progs package.

To fix images in a directory tree recursively, you can apply a script like this:
#!/bin/sh

[ ! -d "$1" ] && echo "usage: $(basename $0) path-to-dir" && exit 1

jpegtran=$(which jpegtran)
[ ! -x "${jpegtran}" ] && echo "Could not find jpegtran." && exit 2
tempfile=$(mktemp)
[ ! -f "${tempfile}" ] && echo "Failed to create temporary file." && exit 3

IFS="
"
for i in $(find "$1" -type f -iname '*.jpg'); do
  output=$(${jpegtran} -optimize -copy none -outfile "${tempfile}" "${i}" 2>&1)
  if [ $? -ne 0 ]; then
    echo "Failed to convert file at \"${i}\"."
    echo "Output: ${output}"
  else
    cp "${tempfile}" "${i}"
  fi
done
rm -f "${tempfile}"

Or if you want a shorter version without much error handling and targeting the current directory:
IFS="
"
tempfile=$(mktemp)
for i in $(find . -type f -iname '*.jpg'); do jpegtran -optimize -outfile "${tempfile}" "$i" > /dev/null 2>&1 && cp "${tempfile}" "$i"; done
rm -f "${tempfile}"

To identify images that have no JFIF marker and should be "fixed", you can run the following command:
IFS="
"
for i in $(find . -type f -iname '*.jpg'); do ! strings "$i" | head -n 10 | fgrep -qs JFIF && echo "Missing JFIF in \"$i\""; done

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Orthogonal Question

My question is orthogonal to your post:

For a given youtube video(e.g. http://www.youtube.com/watch?v=xBWwWx_E9KQ), facebook figures out that the thumbnails exist at this location(e.g. http://i.ytimg.com/vi/xBWwWx_E9KQ/0.jpg). Would you know how does facebook get the thumbnail urls? I couldn't find anything in the source code of the youtube page that indicates where the thumbnails exist; at least nothing that confirms to the facebook standards here(http://developers.facebook.com/docs/share)

Am trying to do the same for one of my web-pages, but in my case, the facebook page pics up not only the image specified in the meta-tag, but it picks up all the images on the entire web-page. Any clue ?

Re: Orthogonal Question

Sorry, don't know the answer. I use the <link rel="image_src" href="..."/> tag and it works for me.