此图显示了以有线电视为源,如何一步步通过各个 Interface接到输出去的。
InputBand是有线电视输入源,ParserBand则是解析器。 PidChannel分为Video和Audio。分别将Video和Audio数据传输向Video Decoder和AudioDecoder。之后,Audio如上一章所讲进入Mixer到DAC。
而Video则通过VideoDecoder解压后显示于Display的VideoWindow上。
代码流程如下:
1. NEXUS_Platform_GetStreamerInputBand(0, &inputBand);
从Platform处得到Streamer InputBand,Platform将参数1(index)0 设置为Tune Stream。
所以参数2(inputBand)返回的是一个InputBand。 它就是Tune Stream。 即位Tune 传入的有线电视信号。
2. 设置Parser:
parserBand = NEXUS_ParserBand_e0;
NEXUS_ParserBand_GetSettings(parserBand, &parserBandSettings);
parserBandSettings.sourceType = NEXUS_ParserBandSourceType_eInputBand;
parserBandSettings.sourceTypeSettings.inputBand = inputBand;
parserBandSettings.transportType = NEXUS_TransportType_eTs;
NEXUS_ParserBand_SetSettings(parserBand, &parserBandSettings);
3. videoPidChannel = NEXUS_PidChannel_Open(parserBand, 0x11, NULL);
打开Pid Channel from parser band.
前面有了ParserBand,并指定了ParserBand的InputBand。这里则打开PidChannel,输入为此ParserBand。
但Sam不明白此处参数2的PID为什么是0x11。(Sam之后发现这个值与音视频流有关,见后面的讲解。)
4. 设置VideoDecoder:
NEXUS_VideoDecoder_GetDefaultStartSettings(&videoProgram);
videoProgram.codec = NEXUS_VideoCodec_eMpeg2;
videoProgram.pidChannel = videoPidChannel;
5. 创建Display并于Platform Output 连接:
NEXUS_Display_GetDefaultSettings(&displaySettings);
displaySettings.format = NEXUS_VideoFormat_eNtsc;
display = NEXUS_Display_Open(0, &displaySettings);
NEXUS_Display_AddOutput(display, NEXUS_ComponentOutput_GetConnector(platformConfig.outputs.component[0]));
NEXUS_Display_AddOutput(display, NEXUS_CompositeOutput_GetConnector(platformConfig.outputs.composite[0]));
if (platformConfig.outputs.svideo[0]) {
NEXUS_Display_AddOutput(display, NEXUS_SvideoOutput_GetConnector(platformConfig.outputs.svideo[0]));
}
6. 创建VideoWindow:
window = NEXUS_VideoWindow_Open(display, 0);
Open a VideoWindow from its Display.
7. 打开VideoDecoder,并将其连接到Video Windows。
vdecode = NEXUS_VideoDecoder_Open(0, NULL);
NEXUS_VideoWindow_AddInput(window, NEXUS_VideoDecoder_GetConnector(vdecode));
8. 开始Decoder:
NEXUS_VideoDecoder_Start(vdecode, &videoProgram);
9. 关闭:
NEXUS_VideoDecoder_Stop(vdecode);
NEXUS_VideoWindow_RemoveAllInputs(window);
NEXUS_VideoInput_Shutdown(NEXUS_VideoDecoder_GetConnector(vdecode));
NEXUS_VideoWindow_Close(window);
NEXUS_Display_Close(display);
NEXUS_VideoDecoder_Close(vdecode);
NEXUS_PidChannel_Close(videoPidChannel);
具体过程很简单:
1.得到Index为0的StreamerInputBand。即是Tune的输入。
2.设置ParserBand。将inputBand设置为ParserBand的Input。
3.打开Video And Audio Pid Channel. NEXUS_PidChannel_Open();
Open a new PID channel from a parser band.
其中参数2:PID:PID (packet ID) that will be selected from the parser band. If TS, this is a PID. If PES, this is a PES stream id.
这个PID的数值,与具体音频视频格式有关。例如,TS流,PS流中各不相同。
有个软件叫做:MediaInfo:它可以查看指定音视频文件的Video,Audio ID。
4. 设置VideoDecoder AudioDecoder的StartSetting。
主要设置codec(视频音频格式)和pidChannel(先前建立的Pid Channel)。
5. 打开AudioDecoder,并将其连接到AudioDAC上。
6. 设置,建立Display.并将Display连接到Display Output(分量,HDMI,混合,S-Video)
7. Open a VideoWindow from its Display. index=0.(NEXUS_VideoWindow_Open)
8. Open a new VideoDecoder.. (NEXUS_VideoDecoder_Open). 并将VideoDecoder加入为VideoWindow的Input。(NEXUS_VideoWindow_AddInput)
9. 开始播放:NEXUS_VideoDecoder_Start,NEXUS_AudioDecoder_Start。
到这里,从Tune中输入出Video,Audio已经完成了。但大家会想,是否可以像之前播放本地Audio那样播放本地的Video File呢?当然是可以的,PlayPump就是做这事的。(Audio Decoder中有对应音频的例子 http://blog.sina.com.cn/s/blog_602f87700100nwlq.html)
思路与之前Audio Decoder类似:
打开,PlayPump, Playback,将PlayPump设置为数据源,利用Playback打开PidChannel。并将PidChannel与VideoDecoder, AudioDecoder联系起来。再将VideoDecoder连到Display的VideoWindow上,通过Display的Output显示在TV上。 AudioDecoder连到Mixer, Mixer中与AudioPlayback混和后进入AudioDAC。
先看图示:
下面看具体步骤:
1. 创建PlayPump, Playback:
playpump = NEXUS_Playpump_Open(0, NULL);
playback = NEXUS_Playback_Create();
讲解:
NEXUS_PlaypumpHandle NEXUS_Playpump_Open(
unsigned index, const NEXUS_PlaypumpOpenSettings *pSettings )
打开一个Playpump Interface。
Open a new Playpump interface.
Broadcom7413支持5个Playpump。 所以Index不能超过4。
NEXUS_PlaybackHandle NEXUS_Playback_Create(void)
创建一个Playback实例。Create a new playback instance.
我们创建这个Playback,用来打开PID Channel。
2. 使用Nexus接口打开视频文件:
file = NEXUS_FilePlay_OpenPosix(fname, NULL);
此FilePlayHandle用来传递给Playback供输入数据源。
3. 设置Playback:
这里主要是设置PlayPump为Playback的playpump. 并设置Playpump的数据传输格式。
NEXUS_Playback_GetSettings(playback, &playbackSettings);
playbackSettings.playpump = playpump; //此处设置playback 的playpump, 用来给Decoder填充数据。
//数据传输格式,包括:MPEG1,DVD VOB,MPEG2-TS(基于传输的),MPEG2-PS(基于存储的)
playbackSettings.playpumpSettings.transportType = NEXUS_TransportType_eTs;
NEXUS_Playback_SetSettings(playback, &playbackSettings);
Sam在使用MediaInfo软件查看目标视频时发现,它是MPEG2-PS。所以修改如下:
playbackSettings.playpumpSettings.transportType = NEXUS_TransportType_eMpeg2Pes;
4. 创建AudioDecoder,并将其连接到DAC:
audioDecoder = NEXUS_AudioDecoder_Open(0, NULL);
NEXUS_AudioOutput_AddInput(
NEXUS_AudioDac_GetConnector(platformConfig.outputs.audioDacs[0]),
NEXUS_AudioDecoder_GetConnector(audioDecoder, NEXUS_AudioDecoderConnectorType_eStereo));
其实此处AudioDecoder也可以连接到Mixer中。
5. 打开Display并指定其Output:
display = NEXUS_Display_Open(0, NULL);
NEXUS_Display_AddOutput(display, NEXUS_ComponentOutput_GetConnector(platformConfig.outputs.component[0]));
6. 创建VideoWindow, VideoDecoder,并将VideoDecoder设置为VideoWindow的Input:
window = NEXUS_VideoWindow_Open(display, 0);
videoDecoder = NEXUS_VideoDecoder_Open(0, NULL);
NEXUS_VideoWindow_AddInput(window, NEXUS_VideoDecoder_GetConnector(videoDecoder));
7. 利用Playback,打开Video PidChannel, Audio PidChannel:
NEXUS_Playback_GetDefaultPidChannelSettings(&playbackPidSettings);
playbackPidSettings.pidSettings.pidType = NEXUS_PidType_eVideo;
playbackPidSettings.pidTypeSettings.video.codec = NEXUS_VideoCodec_eMpeg2; playbackPidSettings.pidTypeSettings.video.index = true;
playbackPidSettings.pidTypeSettings.video.decoder = videoDecoder;
videoPidChannel = NEXUS_Playback_OpenPidChannel(playback, 0x21, &playbackPidSettings);
NEXUS_Playback_GetDefaultPidChannelSettings(&playbackPidSettings);
playbackPidSettings.pidSettings.pidType = NEXUS_PidType_eAudio;
playbackPidSettings.pidSettings.pidTypeSettings.audio.codec = NEXUS_AudioCodec_eMpeg;
playbackPidSettings.pidTypeSettings.audio.primary = audioDecoder;
audioPidChannel = NEXUS_Playback_OpenPidChannel(playback, 0x22, &playbackPidSettings);
首先得到Playback的Default PidChannel的设置,
1.分别指定其PlayPump的Type为Video和Audio。
2.分别指定PlayPump的Codec格式为:NEXUS_VideoCodec_eMpeg2,NEXUS_AudioCodec_eMpeg。 即为:MPEG2-Vidoe和MPEG1/2 -layer 1/2.
3.分别指出PID Channel的Video和Audio的解码器。注意,他们指定的Struct其实并不对应。
4。利用PlayBack打开PidChannel:
注意:PID分别为0x21,0x22. 此处PID与具体媒体格式对应。可以使用MedioInfo查看。
Sam查到自己的视频文件为:0xE0,0xC0.
8. 设置VideoDecoder和AudioDecoder的StrartSetting,并指定各自的PIDChannel:
NEXUS_VideoDecoder_GetDefaultStartSettings(&videoProgram);
videoProgram.codec = NEXUS_VideoCodec_eMpeg2;
videoProgram.pidChannel = videoPidChannel;
NEXUS_AudioDecoder_GetDefaultStartSettings(&audioProgram);
audioProgram.codec = NEXUS_AudioCodec_eMpeg;
audioProgram.pidChannel = audioPidChannel;
指定VideoDecoder Codec和AudioDecoder Codec的格式。即解码器的格式。并指定各自的PIDChannel。
之前PIDChannel得到了VideoDecoder和AudioDecoder。
现在AudioDecoder,VideoDecoder得到对应PIDChannel。有点相互确认的意思。呵呵。
9. 正式开始解码和播放:
NEXUS_VideoDecoder_Start(videoDecoder, &videoProgram);
NEXUS_AudioDecoder_Start(audioDecoder, &audioProgram);
NEXUS_Playback_Start(playback, file, NULL);
如果不处理,会循环播放。可以利用playbackSettings.endOfStreamCallback.callback察看是否播放完毕。完毕则退出。
10。退出:
NEXUS_VideoDecoder_Stop(videoDecoder);
NEXUS_AudioDecoder_Stop(audioDecoder);
NEXUS_Playback_Stop(playback);
NEXUS_FilePlay_Close(file);
NEXUS_Playback_Destroy(playback);
NEXUS_Playpump_Close(playpump);
NEXUS_VideoInput_Shutdown(NEXUS_VideoDecoder_GetConnector(videoDecoder));
NEXUS_VideoDecoder_Close(videoDecoder);
NEXUS_AudioOutput_RemoveAllInputs(NEXUS_AudioDac_GetConnector(platformConfig.outputs.audioDacs[0]));
NEXUS_AudioOutput_RemoveAllInputs(NEXUS_SpdifOutput_GetConnector(platformConfig.outputs.spdif[0]));
NEXUS_AudioInput_Shutdown(NEXUS_AudioDecoder_GetConnector(audioDecoder, NEXUS_AudioDecoderConnectorType_eStereo));
NEXUS_AudioDecoder_Close(audioDecoder);
NEXUS_Display_Close(display);