I am trying to write a simple video-player program to run on a Compaq iPaq H3800, which is a PDA. It has good sound output for headphones, a 6x8 cm (320x240) screen, can last more than two hours even with screen backlight on and busy CPU, and can read big SD memory cards, so it is not absurd to think about using it to watch a movie during a train ride for example. (On my last train ride, a fellow traveller started watching a movie on his cell phone, with a screen at least five time smaller, so...) Anyway, the problem is CPU power: it is a 200 MHz StrongARM, and obviously no GPU, and no FPU either. I did the following benchmarks: - Decoding MP3 (128kbps, 44.1kHz stereo) with MAD takes 180 ms per second (decoding Vorbis using Tremor takes more). - Converting a single frame from YUV40P to the native RGB565 of the framebuffer (using img_convert) takes 18 ms. - Decoding of MPEG4 (XviD with fixed quantizer 6) takes also an average 18 ms per frame. Which means it is possible to play at 22 frame per second, and probably a full 29.97 fps for movies (which will probably only be 320x180 or 320x136). Under those circumstances, decoding wider images and on-the-fly scaling are out of the question, and the video must be transcoded for the occasion. Which leads to the question: which codec to use? Is there a codec with a quality similar to the one of MPEG4, maybe a bitrate a bit larger, but for which decoding require less CPU? And, if there is not, are there options for MPEG4 that can reduce decode-time CPU usage, even at the cost of some quality or bitrate? Any advice would be appreciated. Regards, -- Nicolas George
On Tue, Jul 25, 2006 at 06:36:40PM +0200, Nicolas George wrote:
Anyway, the problem is CPU power: it is a 200 MHz StrongARM, and obviously no GPU, and no FPU either. I did the following benchmarks:
- Decoding MP3 (128kbps, 44.1kHz stereo) with MAD takes 180 ms per second (decoding Vorbis using Tremor takes more).
For tremor make sure you use the "low precision" mode. It's at least 50% faster than the default IIRC.
- Converting a single frame from YUV40P to the native RGB565 of the framebuffer (using img_convert) takes 18 ms.
Maybe try swscale instead? Or does img_convert just wrap swscale now?
- Decoding of MPEG4 (XviD with fixed quantizer 6) takes also an average 18 ms per frame.
xvid uses some rather performance-intensive options by default, probably even B frames unless you disabled them. Try using a lower profile to get better performance, at the cost of worse compression.
Which means it is possible to play at 22 frame per second, and probably a full 29.97 fps for movies (which will probably only be 320x180 or 320x136).
Make sure your widths and heights are always multiples of 16. Otherwise you're just wasting cpu time decoding border pixels which will be cropped.
Under those circumstances, decoding wider images and on-the-fly scaling are out of the question, and the video must be transcoded for the occasion.
Of course.
Which leads to the question: which codec to use?
Is there a codec with a quality similar to the one of MPEG4, maybe a bitrate a bit larger, but for which decoding require less CPU?
You could use mpeg1 for reduced cpu usage. It's actually not _that_ much worse than mpeg4; a lot of the reason people think they're crap is that most encoder suck, but lavc is a very good encoder. Of course try for yourself and see what you think.
And, if there is not, are there options for MPEG4 that can reduce decode-time CPU usage, even at the cost of some quality or bitrate?
The default settings with lavc's mpeg4 encoder produce the bare minimum streams that don't need any extra cpu-intensive stuff to decode. mbd=2, trellis, 2-pass mode, and mv0 options can all increase quality without slowing down decoding. I would recommend against using constant-quantizer. In cpu-limited environments, cpu time needed to decode a frame is roughly proportional to the size of the frame in bits, so trying to keep closer to constant bitrate would probably yield better results. Pure cbr is just a waste of bits though, so I'd go for something in between, just a normal 2pass encode with qmin=4 or 5 perhaps. Rich
Le nonidi 9 thermidor, an CCXIV, Rich Felker a ?crit?:
For tremor make sure you use the "low precision" mode. It's at least 50% faster than the default IIRC.
(for the record, it is a build-time option called --enable-low-accuracy) Thanks for the suggestion. I did some tests, and found that decoding Vorbis in low accuracy mode was negligibly faster than decoding MP3 with mad. And I have read on the web that the low accuracy mode could lead to a very bad background noise. Furthermore, MP3 is more convenient (more standard containers, and a lot of content that would not have to be transcoded). Therefore, I think I will stick to MP3/mad for that task.
Maybe try swscale instead?
swscale with the SWS_FAST_BILINEAR flag is slightly faster than img_convert, but the difference is negligible in front of bitrate variation for example. And swscale.h does not seem to be part of the public API yet.
xvid uses some rather performance-intensive options by default, probably even B frames unless you disabled them.
You are right on both points: XviD uses B-frames by default, and they are a big CPU eater. (I also think they are the reason I found XviD gave better results than lavc, since I did not try to enable them; in fact, at that time, I did not know what they were.)
Make sure your widths and heights are always multiples of 16. Otherwise you're just wasting cpu time decoding border pixels which will be cropped.
Yes, I am aware of that. But the aspect ratio of the content is what it is, I have no control over it.
You could use mpeg1 for reduced cpu usage. It's actually not _that_ much worse than mpeg4; a lot of the reason people think they're crap is that most encoder suck, but lavc is a very good encoder. Of course try for yourself and see what you think.
That is actually a very good suggestion. I tried MPEG1, and on the content I was experimenting with, I could gain 1.5 points of PSNR for a constant CPU usage, at the cost of 60% more bitrate. If that was all, I would just say "so much for the bitrate", and use MPEG1. But there is another problem: mencoder refused to encode the file I was toying with because "MPEG1/2 does not support 18701/780 fps"; I had to change the framerate. Why would a video codec need to know the exact framerate of its content is beyond my understanding; it probably has to do with the fact that MPEG is also a container format. I could use vstrict=-2, but I must say I am not very comfortable with the prospect of my program relying on unsupported features of ffmpeg. On the other hand, just storing a non-standard framerate in the header should be rather safe.
The default settings with lavc's mpeg4 encoder produce the bare minimum streams that don't need any extra cpu-intensive stuff to decode.
That is right, the default setting of lavc'e MPEG4 is 25% faster to decode than the default setting of XviD.
mbd=2, trellis, 2-pass mode, and mv0 options can all increase quality without slowing down decoding.
I did more tests, and I found that cbp is a very interesting option: it enhances slightly the PSNR and reduces the decoding time of about 5%. dia=6 and preme=2 seem to enhance quality without CPU cost. A few others options will increase both the PSNR and the decoding time, in a ratio of about 1/1000 decoding time for 0.01 point of PSNR, mainly v4mv, and the increasing of the bitrate has a similar effect. On the other hand, mpeg_quant is a out of question..
I would recommend against using constant-quantizer. In cpu-limited environments, cpu time needed to decode a frame is roughly proportional to the size of the frame in bits, so trying to keep closer to constant bitrate would probably yield better results. Pure cbr is just a waste of bits though, so I'd go for something in between, just a normal 2pass encode with qmin=4 or 5 perhaps.
Thanks for your advice. I now have a reasonably clear view of what I should do. Anyway, I do not need to make an absolute choice right now, especially since it does not seem possible (or at least, supported) to build a libavcodec without support for a bunch of codecs. I will give news of the progress of my program. Regards, -- Nicolas George
On Wed, Aug 02, 2006 at 06:19:52PM +0200, Nicolas George wrote:
Make sure your widths and heights are always multiples of 16. Otherwise you're just wasting cpu time decoding border pixels which will be cropped.
Yes, I am aware of that. But the aspect ratio of the content is what it is, I have no control over it.
Just round to a multiple of 16. The tiny deviation in aspect will be less offensive than the alternatives (wasted performance/quality).
If that was all, I would just say "so much for the bitrate", and use MPEG1. But there is another problem: mencoder refused to encode the file I was toying with because "MPEG1/2 does not support 18701/780 fps"; I had to change the framerate. Why would a video codec need to know the exact framerate of its content is beyond my understanding; it probably has to do with the fact that MPEG is also a container format.
Yes, it's being stupid, but maybe your specification of the framerate is also imprecise if it's coming out as 18701/780..
I could use vstrict=-2, but I must say I am not very comfortable with the prospect of my program relying on unsupported features of ffmpeg. On the other hand, just storing a non-standard framerate in the header should be rather safe.
IMO this is not much of a problem actually unless you're trying to make a dvd or vcd.
Thanks for your advice. I now have a reasonably clear view of what I should do. Anyway, I do not need to make an absolute choice right now, especially since it does not seem possible (or at least, supported) to build a libavcodec without support for a bunch of codecs.
It's supposed to be possible.. Rich
Hi On Sat, Aug 05, 2006 at 04:18:49AM -0400, Rich Felker wrote: [...]
If that was all, I would just say "so much for the bitrate", and use MPEG1. But there is another problem: mencoder refused to encode the file I was toying with because "MPEG1/2 does not support 18701/780 fps"; I had to change the framerate. Why would a video codec need to know the exact framerate of its content is beyond my understanding; it probably has to do with the fact that MPEG is also a container format.
Yes, it's being stupid, but maybe your specification of the framerate is also imprecise if it's coming out as 18701/780..
I could use vstrict=-2, but I must say I am not very comfortable with the prospect of my program relying on unsupported features of ffmpeg. On the other hand, just storing a non-standard framerate in the header should be rather safe.
IMO this is not much of a problem actually unless you're trying to make a dvd or vcd.
it depends on the container, if you store mpeg-1/2 in mpeg-ps/ts then u MUST use the standard framerates, as another framerate simply cannot be stored in the header, there are a few unofficial rates like 15 and 10fps but except these most decoders will be quite unhappy with the file, also keep in mind that mpeg-ps/ts does NOT have timestamps per frame, mpeg-ps/ts just requires timestamps once every 0.5 seconds and it _cannot_ store more then one per "packet" and packets in mpeg-ps/ts are just pieces of the bitstream they are not aligned to the start or end of frames, so a frame can be spread over several packets and packets can contain several frames if OTOH you store mpeg-1/2 in a generic container be it avi, nut, mkv or such then a non standard framerate will probably work with the few players which support mpeg-1/2 in such containers [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB In the past you could go to a library and read, borrow or copy any book Today you'd get arrested for mere telling someone where the library is
participants (3)
-
dalias@aerifal.cx -
michaelni@gmx.at -
nicolas.george@ens.fr