Differences between revisions 36 and 37
Revision 36 as of 2010-11-21 17:01:56
Size: 14762
Editor: jason
Comment:
Revision 37 as of 2010-11-21 17:03:55
Size: 14786
Editor: jason
Comment:
Deletions are marked like this. Additions are marked like this.
Line 121: Line 121:
 . `cx88ir_load="YES"`
Line 133: Line 135:
=== Tuner Firmware === == Tuner Firmware ==

Capture App Examples

Tune to channel 4 in the default profile and send MPEG transport stream to VLC at port 8802 and to a file at ~/out.m2t:

  • Shell 1:
    • vlc udp://@127.0.0.1:8802

    Shell 2:
    • cx88 -d /dev/cx88mpeg0 -u udp://localhost:8802 -u file://${HOME}/out.m2t -x /usr/local/share/examples/cx88/cx88.xml.sample -c 4

Tune to channel 45 in the DVBT_EU_UHF profile, send MPEG transport stream to /home/user/out.m2t, and automatically terminate capture after 28.7 minutes:

  • cx88 -d /dev/cx88mpeg0 -u udp://localhost:8802 -u file:///home/user/out.m2t -x /usr/local/share/examples/cx88/cx88.xml.sample -c DVBT_EU_UHF:45 -n 28.7

Capture audio only from channel 42 in the USA profile and send to sound card at /dev/dsp0:

  • cx88 -d /dev/cx88audio0 -u oss:///dev/dsp0 -x /usr/local/share/examples/cx88/cx88.xml.sample -c USA:42

Capture audio only from channel 42 in the USA profile and use a third-party app to handle the actual playback:

  • cx88 -d /dev/cx88audio0 -x /usr/local/share/examples/cx88/cx88.xml.sample -c USA:42

Capturing Raw Video

The best way I've found to capture raw video (e.g. from an analog TV station) is to use a named pipe to send the video frames to ffmpeg for encoding to an mpeg file. Future version of cx88 may have a live capture facility that can display the raw pixels directly to the screen (e.g. using SDL). The output from ffmpeg may also be piped into a player such as VLC for live viewing, but this is rather inefficient and multiple users have reported that live analog playback with VLC is very jittery.

  • Capture video and audio from channel 42 in the USA profile and send to ffmpeg for encoding via a named pipe:
    • Shell 1:
      • mkfifo vpipe

      • ffmpeg -f oss -ar 48000 -ac 2 -i /dev/dsp1 -deinterlace -b 10000k -pix_fmt yuv422p -s 640x480 -r 30 -f rawvideo -i vpipe -vcodec mpeg2video -acodec libmp3lame -y ch42.mpg

      Shell 2:
      • cx88 -c 42 -d /dev/cx88video0 -u file://${PWD}/vpipe -d /dev/cx88audio0 -x /usr/local/share/examples/cx88/cx88.xml.sample

As in the above example, ffmpeg can be used to multiplex the audio and video output. The ffmpeg command above uses the OSS-compatible cx88 audio interface, and assumes that /dev/dsp1 is the OSS audio device that corresponds to cx88audio0. It also assumes that cx88video0 and cx88audio0 are the video and audio functions of the same capture card. Note that in the cx88 command, only the video data is sent to the named pipe.

ffmpeg can be a little daunting, so let's dissect the ffmpeg command:

  • The "-f oss -ar 48000 -ac2 -i /dev/dsp1" sequence specifies the audio properties--it tells ffmpeg to capture from /dev/dsp1 using an OSS interface, and to use a bit rate of 48KHz with 2 channels (stereo).
  • The "-deinterlace" option tells ffmpeg to compensate for motion artifacts caused by analog video broadcast interlacing--this is not strictly necessary
  • The "-b 10000k" option tells ffmpeg to encode the video at a bitrate of 10000kbps--I've found that anything over ~4000k yields generally high quality, while anything significantly lower will produce a noticeably blocky video.
  • The "-pix_fmt yuv422p" option tells ffmpeg that each incoming frame is in the planar YUV422 pixel format--this is the format that the cx88 app currently specifies to the driver. Future version may support an pixel format option, using the -o switch.
  • The "-s 640x480 -r 30" sequence tells ffmpeg that the incoming video has a resolution of 640x480 pixels with a frame rate of 30 fps. This is compatible with the NTSC video system; for PAL/SECAM, you would probably want to use "-s 768x576 -r 25"
  • The "-f rawvideo -i vpipe" sequence tells ffmpeg that the incoming video consists of raw pixel frames, originating from a file named "vpipe"
  • The "-vcodec mpeg2video -acodec libmp3lame" tells ffmpeg to use the MPEG-2 format with mp3 audio when encoding the mpeg file.
  • "-y ch42.mpg" tells ffmpeg to store the encoded mpeg video in a file named ch42.mpg.

Capturing Raw Video for direct viewing

Here is a similar example to the above that uses mplayer to directly show the captured raw video (tho in this case playing PAL instead of NTSC):

Shell 1:

  • mkfifo vpipe

  • mplayer -demuxer rawvideo -rawvideo w=768:h=576:format=422p:size=884736 -vf swapuv,scale=-1:-1 vpipe

Shell 2:

  • cx88 -c 42 -d /dev/cx88video0 -u file://${PWD}/vpipe -d /dev/cx88audio0 -x cx88.xml

(This needs a custom cx88.xml that defines a profile that's using PAL, I actually only tested this with composite in and without audio so far - using a small hack to the source that enables capturing from non-tuner inputs, see this thread for the details including the patch and the cx88.xml I used:

)

For NTSC, the equivalent probably would be (cannot test):

Shell 1:

  • mkfifo vpipe

  • mplayer -demuxer rawvideo -rawvideo w=640:h=480:format=422p:size=614400 -vf swapuv,scale=-1:-1 vpipe

Shell 2:

  • cx88 -c 42 -d /dev/cx88video0 -u file://${PWD}/vpipe -d /dev/cx88audio0 -x /usr/local/share/examples/cx88/cx88.xml.sample

Raw Video Picture-In-Picture (PiP)

As one of my friends pointed out when I told him I added PiP support to cx88, this is a rather ridiculous feature. Analog video is gradually going away, and at any rate the chances of anyone having two tuner cards and two programs that they want to watch simultaneously are practically NIL. This feature was intended as a proof-of-concept to demonstrate that the cx88 driver's buffering system was flexible enough to handle hardware-based picture overlay. And because the buffer composition is handled directly by the CX2388x DMA engine, it may not work correctly when DMA bounce buffers are used (nothing bad or dangerous will happen, but parts of your video may be garbled if the bounce buffers prevent the two DMA engines from using the same physical location in memory).

But in case anyone cares, here's how you do PiP with the cx88 capture app:

  1. Run ffmpeg just as in the example above.
  2. Run cx88 as follows:
    • cx88 -c 42 -d /dev/cx88video0 -o "buffer=0;pip=/dev/cx88video1" -u file://${HOME}/vpipe -d /dev/cx88audio0 -x /usr/local/share/examples/cx88/cx88.xml.sample

When the application starts, both tuners will tune to channel 42. However, you can use the 'c' command to change the channels on each tuner individually--simply separate the channel strings for the primary and secondary tuners with a semicolon. To change just the primary channel, you can still use a normal channel string, e.g. "42" or "USA:42". To change just the secondary channel, prefix the channel string with a semicolon, e.g. ";USA:54". To change both simultaneously, use something like "USA:42;USA:54".

Optimizing Performance

As mentioned in the General Architecture section, the CX2388x has onboard SRAM that is used for driver-configurable FIFOs and is shared between all functions. The cx88 driver will allocate the SRAM based on the functions that are actually present and have drivers attached. So if, for example, you have a card that supports MPEG, video, and audio, but you only care about digital TV, then just load the cx88mpeg driver. If you don't load the cx88video or cx88audio drivers, the MPEG driver will receive all the SRAM.

But there are some other things you can do for more complex use cases. If you have two tuner cards and you want to use one only for digital TV and the other only for analog TV, then you can optimize the SRAM allocation on each card by disabling the audio & video functions on the digital-only card, and the MPEG function on the analog-only card. The cx88 driver respects FreeBSD's "disabled" device hint, so you can do something like the following:

  • hint.cx23880mpeg.0.disabled="1" #disable MPEG function on analog-only card

  • hint.cx88video.1.disabled="1" #disable video function on digital-only card

  • hint.cx88audio.1.disabled="1" #disable audio function on digital-only card

Like all device hints, this operates on internal device-tree names, not device node names. For driver versions 1.2 and later, this means that CX23880-family MPEG TS devices will use the name "cx23880mpeg" instead of "cx88mpeg". For CX23885-family devices, use the name of the bridge device, e.g. "cx23885b0".

The raw video driver supports further optimization of SRAM allocation by allowing you to disable the planar and VBI DMA channels (and therefore their SRAM allocations) if you don't plan on using them:

  • hint.cx88video.0.noplanar="1"

  • hint.cx88video.0.novbi="1"

You can either add the above hints to /boot/device.hints and reboot, or you can add them on-the-fly using kenv(1). Note that these hints are only checked when the driver is loaded, so if you want kenv(1) settings to take effect you'll need to reload the cx88 kernel modules.

I2C Performance

As mentioned in the General Architecture section, the cx88 driver uses hardware-controlled I2C transactions for frontend devices. The hardware I2C facilities on the CX23888x are unable to perform large batch transfers, so an interrupt needs to be generated for roughly every byte that is transferred across the I2C bus. Because I2C is slow (100KHz), this approach still reduces CPU utilization and improves responsiveness when compared to a polled software-controlled approach. However, during large transfers (such as tuner firmware loads), the large number of interrupts may be disruptive toward real-time applications.

Alternatively, the I2C interface may be placed in polling mode. This simply disables I2C interrupts and polls the I2C status registers for transfer completion. This polling incurs more CPU load, but it happens at normal thread priority. To use it, set the "i2c_polling" hint to 1. This hint must be applied to I2C control device. For the CX23880 family, this is just the device that attached to the relevant PCI function, e.g. "hint.cx88video.0.i2c_polling=1" or "hint.cx23880mpeg.0.i2c_polling=1". Since the CX23885 family has multiple I2C masters, a cx23885i2c device must be created for each master, so you would use something like "hint.cx23885i2c.0.i2c_polling=1".

Message Signaled Interrupts (MSIs)

The CX23885/7/8 family supports both MSIs and legacy PCI-style interrupts as required by the PCI-express spec. Enabling MSIs will ensure the cx88 device does not share an interrupt line with any other device. By default, MSIs are disabled for the CX23885 devices, as some older motherboards do not support them correctly, and the CX23885/7/8 themselves have some bugs where MSIs are concerned. To enable them, use the "msi" hint on the CX23885 bridge device, e.g. "hint.cx23885b.0.msi=1". To check if MSIs have been enabled for your device, examine the output of "vmstat -i". The "cx23885b" device corresponding to your hardware should be assigned an IRQ number of 256 or greater.

NOTE: Only use MSIs if you really know what you are doing. I especially do not recommend enabling MSIs for devices that specifically use the CX23885 (the oldest chip in the CX23885/7/8 family). With MSIs enabled, my CX23885 card works 90% of the time, but the other 10% of the time the captures will fail to start because the interrupts don't fire correctly. Sometimes this will even cause a "Fatal trap 30" kernel panic, which basically means the device fired an interrupt but not to the correct vector. This seems to be a hardware bug that is isolated to the CX23885; my CX23887 and CX23888 cards have never had this issue. Beyond that, all three chips in the family seem to be unable to handle MSIs in rapid succession; because of this, interrupt-driven I2C transfers simply won't work, so enabling MSIs will force the I2C buses into polling mode. Singular streaming captures will work fine because they fire interrupts at evenly-spaced, wide intervals. But simultaneous captures from the same card may see this issue if the streams interrupt at different rates (e.g. MPEG TS and analog audio).

Access by non-root users

As with most drivers, the cx88 device nodes are added to the /dev directory with permissions that only allow them to be controlled by the owner (root). If you'd like to allow non-root users to perform captures with cx88 devices, you can use devfs.rules(5) to do so. For example, I have the following entries in my /etc/defaults/devfs.rules:

  • add path 'cx88*' mode 0660 group wheel

  • add path 'cx23885*' mode 0660 group wheel # CX23885-family stream configuration device

  • add path 'iicdev*' mode 0660 group wheel

Loading kernel modules at boot

For CX23880/1/2/3-based PCI cards, add one or more of the following to /boot/loader.conf:

  • cx88mpeg_load="YES"

  • cx88video_load="YES"

  • cx88audio_load="YES"

  • cx88ir_load="YES"

For CX23885/7/8-based PCIe cards, add *both* of the following to /boot/loader.conf:

  • cx23885avfw_load="YES"

  • cx23885_load="YES"

Automatically rebuild kernel modules whenever you rebuild your kernel

Add the following to /etc/make.conf:

  • PORTS_MODULES=multimedia/cx88

Tuner Firmware

Since loading tuner firmware files can be an expensive operation, libtuner has a firmware mechanism that is designed to load firmware only when necessary, for example when switching a broadcast mode necessitates a different firmware file or a firmware file has been updated. To track firmware file updates, libtuner may attempt to generate a timestamp file in the same directory as the tuner firmware. This timestamp may subsequently be used to prevent unnecessary re-loading of the firmware. The firmware files should therefore be stored in a directory that is writable by the user of the capture app. The firmware load will not fail if the directory is not writable, but unnecessary firmware re-loads may be incurred.

Programming Examples

Sample code is provided in /usr/local/share/examples/cx88. The C++ source files in this directory contain code for audio, video, and MPEG capture using the pcHDTV HD-3000 and HD-5500 cards, though they may easily be modified to use other cards. And of course the sources for the capture app are available. To compile any of these files, use a command line like the following:

  • g++ -Wall -O2 -I/usr/local/include/cx88 -I/usr/local/include/libtuner -L/usr/local/lib/libtuner -ltuner -o <executable> <source_file>


CategoryTemplate

Overview/TipsAndTricks (last edited 2011-11-08 21:24:50 by jason)