I want to mimic the bing video preview functionality, with a thumbnail preview, then onMouseOver, load and play a video file. I plan to use VideoJS (html5 + flash) for the video playback. I need to use ffmpeg to produce these video files.
How can I create a mp4 preview with video only, which contains 1s of every other minute of the full clip, and shrink resolution to a fixed width (maintaining aspect ratio, preferably with zoom crop) using php + ffmpeg command line?
I'm assuming it can be done somehow along the lines of cutting 1s clips, then combine the smaller clips, and re-encode for a final rescaled output.
*Edit: Using ffmpeg is a design requirement. Pulling out 1s clips, should be fairly easy, but combining them seems to be somewhat complex with ffmpeg. I don't want cycling thumbnails, I want a video preview which contains a number of 1s clips. Eg. runtime in seconds: 100-101, and 200-201 combined in a heavily compressed clip. I am asking for a command line example of how to do this in an efficient manner.
One way to do this in Windows (or wine) would be to use an Avisynth script. This would allow you to do all your desired transformations in one step. It's been a little while since I've used Avisynth but a very simple script might look like:
DirectShowSource("C:\file\to\encode.avi", audio=false) # Or another source filter
SelectRangeEvery(1440, 24) # outputs 24 frames every 1440 frames
BilinearResize(320,240) # resize to your desired resolution
Crop(...) # crop to reach desired aspect ratio
This could be extended to support various framerates and aspect ratios instead of hardcoding everything. The resulting .avs file can then be used as an input file to ffmpeg, provided that it has been compiled with --enable-avisynth.
I've an approach and i think that will work...
Using ffmpeg you can get thumbnails of the video at specific intervals.
So i will take about 5 to 10 thumbnails in the interval of 2 seconds and store them on my server with a unique name that identifies the video.
So when I mouse over i call the function which will load these images sequentially(which makes the user feel the video is fast forwarding..)
But in this format, we can't play sound when we mouse over ..
I don't know whether this is good but i know this will work..
Update:
I think it will be better to create a video using ffmpeg using the extracted images and play them while we mouse over.. This will be quite faster than loading a sequence of images. ffmpeg can be used to create a new video from a list of images.
I managed to do this now, by pulling out 1s clips, and convert them to mpeg. Then combine these mpeg files, by appending them into a single file. Then convert til mpeg file to mp4
Related
I would like to insert still images into a mp4 sequence by PHP on server side, where the position of the placed image would move, for example I'd place an image into a photo frame with chroma-key color (or specified coordinates) in a room and the position of this photo frame would move in the video (if possible..). Much similar to Facebook's "Friends Day" Video. See this example link.
Is there any class or function that would allow me to do so?
Check-ed out this previous question but seemed inconclusive? Inserting an image inside a video at particular position via PHP and a video extension
Thanks in advance for your help!
You're gunna need more than PHP. You need to understand some things about pixel programming and its sub-category : computer vision.
Before I show you the reality check, let's assume the task is really as simple as to just "...Insert still images into a mp4 sequence by PHP". What would you need?
Try PHP :
If you prepare your input footage to have something like a green colour box where image should be inserted then you can consider this PHP method for replacing the green pixels with user photo.
You will have to do this for every single frame. To get video broken down to single frame PNGs try a tool like FFmpeg...
Try FFmpeg :
First have FFmpeg installed on your server (there's even a FFmpeg to PHP connection, ie: send commands and receive the result). This will be used to extract from source, overlay images and later encode the new output video. You can see this answer for overlaying images at specific positions.
In the snippet below, two input images are specified (vid_frame1.png is a video grab which needs an image to be inserted, over_image1.png is the to-be-overlaid image). overlay=75:200 means position overlay image at 75px across (x) and 200px down (y).
ffmpeg -i vid_frame1.png -i over_image1.png -filter_complex "[0:v][1:v] overlay=75:200" new_frame1.png
As you can see, you have to specify the position so in a moving video (where placement position will change over time) you need to keep track of expected image position in each frame. In a 24 FPS video that means a possible 24 unique positions per second which might get tedious. You would run the above command 24 times, each time changing the overlayposition.
note : If you install FFmpeg and use it with PHP then you could also do a stdinput / stdoutput process. This means you can output directly to video file instead of outputting "edited frame" PNGs. The video is generated as your program runs and when it's finish, there's a complete video file. This is too long to explain but you can information about it.
The reality check...
What you're talking about is called "dynamic video". You need a system in place to handle tasks like pixel tracking, perspective distortion and motion blur amongst others. This system would be a server based app (made using Java? or C#?). Here is one example of a dynamic editing tool. Also try coding something like this distortion tool (found here) so if we take that green block idea, now you simply find the four corners of green block in source video frame and position those distort points to each corner and you have persective distortion etc. For motion blur via PHP (I never tried that but) there is Google search...
Let me explain what I am trying to do, I am building a command line tool with PHP that uses these programs to optimize images for the web...
imagemagick to determine file type and convert non-animated gif's to png
gifsicle to optimize Animated Gif images
jpegtran to optimize jpg images
pngcrush to optimize png image
pngquant to optimize png images to png8 format
pngout to optimize png images to png8 format
This is a pretty heavy process to be running, luckily it is done very infrequently but I would still like to optimize as much as I can.
Right now to process around 12 images takes roughly 76 seconds. So you can see it is a slow process, imagine 100 images.
I would really like to somehow, mark an image as optimized somehow, so when I am loading a batch of images, the first thing it does is run through ImageMagick to get the exact file type, would be nice if I could somehow embed a message that says this image is already optimized as much as it can be, and then when I am reading images in, if it detects a message it will know to not waste valuable time running that particular image through all the other programs, if this is possible, it could greatly increase speed.
Please help me, I am not used to working with images like this, is this possible even, if it is what is it called and how could I achieve it?
Thanks for any help
If you were to include a flag in the image itself then that would be served to the clients. It would add to the filesize of your images thus negating some of your optimisation.
Suggestions
Keep a reference of the status
Keep a catalog in a file in the same directory - much like the Windows Thumbs.db file.
Another option would be to keep the record in a database or datastore such as Redis or Memcached.
Move after processing
You could move the files to a different directory once they are processed (as #Jordan mentions).
Change the filename to indicate it is processed
Another option would be to append an extra "extension" onto the file name for example:
my_image.processed.jpg
Embedding data in images
Steganography
Usually this is used for attempting to hide covert data in an image and it is called Steganography. It is not really suited to this use case however.
EXIF data
You could write it into the EXIF data of an image, but this would be JPEG and TIFF only as far as I am aware. There is a PHP library available called PEL for writing and reading EXIF data.
You could use the Comment field to tag your image as already optimised, like this:
convert x.jpg -set comment "Optimised" x.jpg
Then, when you are processing, you can extract it like this:
identify -format "%c" x.jpg
Optimised
I have one basic question. I have project where I need more sizes of one picture.
Yes... During uploading you make thumbnails... and so on... I know this story ... performance vs. storing possibilities.
So I save original img, a make 2 thumbnails copies for example max width 100px and maxwidht 200px with respect to ratio.
Now I need show image in 150px max width so I take saved img(200px) and .....
I use getimagesize() for calculating showing width and height respected to ratio,
or I set max-widht and max-height and I leave it for browser (browser make it for me),
or I set width a keep height: auto (but I want also limit max height)
So actualy I use php and getimagesize() but this function every time work with file and I am little scared. When you process 1 img it is OK but what about 20 or 100.
And... another idea, while uploading I save to DB also size information, for this I have to save data for 3 img (now only original one) this complicate everything.
So ... any ideas? What is your practice? THX.
Two images, at a maximum: A thumbnail, and the original image are sufficient. Make sure that your upload page is well-secured, because I've seen a website taken down through DoS (abusing an unprotected image-resizing page). Also limit the maximum upload size, to prevent abuse.
You can use the max-width and max-height CSS properties to limit the size of your images.
My approach
I wrote a pretty simple gallery application in php a while ago and this is how it works:
The images are stored in a folder with subfolders representing albums (and subalbums). They are uploaded via FTP and the webserver only has read-permissions on them.
For each image there are three versions:
a full one (the original)
a "mid" one (1024x768px max)
a "thumb" one (250x250px max)
All requests for images by the browser are served by php, and not-yet-existing versions are generated on the fly. The actual data is served through X-Sendfile, but that's an implementation detail.
I store the smaller versions in separate directories. When given a path to an original image, it is trivial to find the corresponding downscaled files (and check for existence and modification times).
Thoughts on your problem
Scaling images using HTML / CSS is considered bad practice for two simple reasons: if you are scaling up, you have a blurred image. If you are scaling down, you waste bandwidth and make your page slower for no good reason. So don't do it.
It should be possible to determine a pretty small set of required versions of each file (for example those used in a layout as in my case). Depending on the size and requirements of your project there are a few possibilities for creating those versions:
on the fly: generate / update them, when they are requested
during upload: have the routine that is called during the upload-process do the work
in the background: have the upload-routine add a job to a queue that is worked on in the background (probably most scalable but also fairly complex to implement and deploy)
Scaling down large images is a pretty slow operation (taking a few seconds usually). You might want to throttle it somehow to prevent abuse / DoS. Also limit dimensions and file size. A 100 MP (or even bigger) plain white (or any color) JPG might be very small when compressed, but will use an awful lot of RAM during scaling. Also big PNGs take really long to decompress (and even more to compress).
For a small website it doesn't matter, which approach you choose. Something that works (even if it doesn't scale) will do. If you plan on getting a good amount of traffic and a steady stream of uploads, then choose wisely and benchmark carefully.
I have a sort of a canvas on my site, (not canvas though for the need of support in IE) where images are loaded to and modified.
At the end of the process I'd like to take all the files used in the canvas and connect them into a (bigger) jpg.
My thoughts were to collect all the relative positions of the images and use it to reposition them on the new file.
I should add as well that one of the files is a background image.
layers should not count more than lets say 4 including the background.
on top of that i needed to jpg-ize a text layer as well but for that I have a php script, if anyone has an efficient way to do it I'll be glad to see it as well.
Look at GD or ImageMagic PHP extensions. Both allow to do that.
Here is an example of how to do image overlays in imagemagick. You can specify the scaling and position of the overlay in the convert parameters.
I have a large SVG file (approx. 60 MB, 10000x10000 pixels but with the potential to get much larger), and I'm wanting to create, say, many tiled 256x256 PNG images from it (in that example there would be 1600 images; round(10000/256)^2).
Does anyone have any idea of how to do this on a web server (running PHP amongst other things)? I thought about rsvg, but it doesn't seem to have any functionality to modify the bounding box (and I'd rather avoid doing it manually for each section). ImageMagick might be able to do it, but I've not been having much luck with getting it to work. Using rsvg to create a large PNG and then using a tool dedicated to tiling very large images might work, but I've not had any luck finding such a thing! Speed isn't really an issue, although it is desirable, so if the worst comes to the worst, I might look into modifying the SVG's bounding box per section. I could see the generation taking forever, though!
Anyone know of any methods to do this?
Edit 2016-03-02:
I recently came back to needing an answer for this question again, and Inkscape appears to be the only tool which can render SVGs for a given area at given sizes (svgexport almost meets these requirements, but it doesn't let you change the aspect ratio).
My aim was to tile an SVG into 256x256 tiles, and I've now successfully made a script which can tile an arbitrarily large SVG by doing repeated renderings in inkscape of about 16,000 x 16,000 and tiling the resulting images. I've successfully rendered SVGs where the dimensions are over 500,000 x 500,000 pixels—no problems with memory usage (it just takes a long time!)
inkscape has a command line mode to export pngs, taking an optional argument to choose which area to export
inkscape vector.svg --export-png=raster.png --export-area=0:0:100:100
I'd look at Apache Batik. In particular, their SVG Rasterizer looks like just what you need.
I've never used it for giant SVG files, though, so I don't know if it's optimized for that case or not.
Check out this question i posted earlier and got working.
If the image is only 10000x10000 the script i have in the question works best.
If however you want to use much bigger images check out the script in my anser.
ImageMagick crop huge image
PanoJS seems to do what you're asking about. You need to convert the SVG to a large PNG first though (e.g. using inkscape on the command line), and then use PanoJS's tilemaker to make the tiles. It is a very memory intensive beast, but if you can get it to run successfully, you can then use the PanoJS Javascript code to point to your webserver. XKCD used it for a large image describing money.
You might want to edit the source properties of your SVG (a copy), to render certain areas only. Use the "width" and "height" properties to match your desired tile size (256) and the "viewBox" to the desired tile area (for example 'viewBox="512 256 768 512"' for the 3rd tile in the second row).
You could do something like this in a loop:
$sed = "sed 's/width=\"10000\"/width=\"256\"' ".$sourcefile;
$sed .= " | sed 's/height=\"10000\"/height=\"256\"'";
$sed .= " | sed 's/viewBox=\"0 0 10000 10000\"/viewBox=\"0 0 256 256\"'";
exec($sed." > ".$tmpfile);
exec('rsvg '.$tmpfile.' > '.$tilefile);
I don't know how this behaves on very large files though.