views:

1099

answers:

4

I want my website to join some webcam recordings in FLV files (like this one). This needs to be done on Linux without user input. How do I do this? For simplicity's sake, I'll use the same flv as both inputs in hope of getting a flv that plays the same thing twice in a row.

That should be easy enough, right? There's even a full code example in the ffmpeg FAQ.

Well, pipes seem to be giving me problems (both on my mac running Leopard and on Ubuntu 8.04) so let's keep it simple and use normal files. Also, if I don't specify a rate of 15 fps, the visual part plays extremely fast. The example script thus becomes:

ffmpeg -i input.flv -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 \
  - > temp.a < /dev/null
ffmpeg -i input.flv -an -f yuv4mpegpipe - > temp.v < /dev/null
cat temp.v temp.v > all.v
cat temp.a temp.a > all.a
ffmpeg -f u16le -acodec pcm_s16le -ac 2 -ar 44100 -i all.a \
  -f yuv4mpegpipe -i all.v -sameq -y output.flv

Well, using this will work for the audio, but I only get the video the first time around. This seems to be the case for any flv I throw as input.flv, including the movie teasers that come with red5.

a) Why doesn't the example script work as advertised, in particular why do I not get all the video I'm expecting?

b) Why do I have to specify a framerate while Wimpy player can play the flv at the right speed?

The only way I found to join two flvs was to use mencoder. Problem is, mencoder doesn't seem to join flvs:

mencoder input.flv input.flv -o output.flv -of lavf -oac copy \
-ovc lavc -lavcopts vcodec=flv

I get a Floating point exception...

MEncoder 1.0rc2-4.0.1 (C) 2000-2007 MPlayer Team
CPU: Intel(R) Xeon(R) CPU 5150 @ 2.66GHz (Family: 6, Model: 15, Stepping: 6)
CPUflags: Type: 6 MMX: 1 MMX2: 1 3DNow: 0 3DNow2: 0 SSE: 1 SSE2: 1
Compiled for x86 CPU with extensions: MMX MMX2 SSE SSE2

success: format: 0 data: 0x0 - 0x45b2f
libavformat file format detected.
[flv @ 0x697160]Unsupported audio codec (6)
[flv @ 0x697160]Could not find codec parameters (Audio: 0x0006, 22050 Hz, mono)
[lavf] Video stream found, -vid 0
[lavf] Audio stream found, -aid 1
VIDEO: [FLV1] 240x180 0bpp 1000.000 fps 0.0 kbps ( 0.0 kbyte/s)
[V] filefmt:44 fourcc:0x31564C46 size:240x180 fps:1000.00 ftime:=0.0010
** MUXER_LAVF *****************************************************************
REMEMBER: MEncoder's libavformat muxing is presently broken and can generate
INCORRECT files in the presence of B frames. Moreover, due to bugs MPlayer
will play these INCORRECT files as if nothing were wrong!
*******************************************************************************
OK, exit
Opening video filter: [expand osd=1]
Expand: -1 x -1, -1 ; -1, osd: 1, aspect: 0.000000, round: 1
==========================================================================
Opening video decoder: [ffmpeg] FFmpeg's libavcodec codec family
Selected video codec: [ffflv] vfm: ffmpeg (FFmpeg Flash video)
==========================================================================
audiocodec: framecopy (format=6 chans=1 rate=22050 bits=16 B/s=0 sample-0)
VDec: vo config request - 240 x 180 (preferred colorspace: Planar YV12)
VDec: using Planar YV12 as output csp (no 0)
Movie-Aspect is undefined - no prescaling applied.
videocodec: libavcodec (240x180 fourcc=31564c46 [FLV1])
VIDEO CODEC ID: 22
AUDIO CODEC ID: 10007, TAG: 0
Writing header...
[NULL @ 0x67d110]codec not compatible with flv
Floating point exception

c) Is there a way for mencoder to decode and encode flvs correctly?

So the only way I've found so far to join flvs, is to use ffmpeg to go back and forth between flv and avi, and use mencoder to join the avis:

ffmpeg -i input.flv -vcodec rawvideo -acodec pcm_s16le -r 15 file.avi
mencoder -o output.avi -oac copy -ovc copy -noskip file.avi file.avi
ffmpeg -i output.avi output.flv

d) There must be a better way to achieve this... Which one?

e) Because of the problem of the framerate, though, only flvs with constant framerate (like the one I recorded through facebook) will be converted correctly to avis, but this won't work for the flvs I seem to be recording (like this one or this one). Is there a way to do this for these flvs too?

Any help would be very appreciated.

A: 

You'll encounter a very subtle problem here because most video and audio formats (especially in ordinary containers) use "global headers," meaning at the start of the file they have a single header which specifies compression information (like width, height, etc) for the whole file. Concatting two streams will clearly fail, as it will now have two headers instead of one and the muxer may not like this. Converting to AVI probably is resolving the issue in your case because mencoder has code to concat AVIs--that code properly handles the header issue.

Dark Shikari
I've edited my text to use "join" instead of "concatenate".
Marc-André Lafortune
A: 

dont know if this will actually work but try using this command :

cat yourVideos/*.flv >> big.flv

this will probably damage meta information so after executing that command use "flvtool" (ruby script you can find it with google) to fix it.

As pointed out by Dark Shikari, this won't work. Metadata information could be reset, but there would be extra headers which will corrupt the resulting file. Even if we skip the extra headers, the audio and video blocks have timestamps that need to be offset.
Marc-André Lafortune
A: 

After posting my question on mencoder's mailing list, trying other things, praying and otherwise wasting hours on this, I resorted to... write my own tool! I started from flvtool and after some digging in the code (no doc whatsoever, source included) and writing ~40 lines of code, it works, with no loss in quality (since there is no transcoding).

I'll release it asap, in the meantime anyone interested can contact me.

Marc-André Lafortune
Please add those 40 lines to your question and close it.
bzlm
Or better yet, start a project for it on <insert your favorite open-source repository here>.
Jacob
Since I can't 'accept answer' on my own answers, I'm not sure how I can close this question...
Marc-André Lafortune
+1  A: 

I thought it would be a nice learning exercise to rewrite it in Ruby.

It was.

Six months later and three gems later, here's the released product.

I'll still be working a bit on it, but it works.

Marc-André Lafortune