1 /*
2 * real_encoder.cc --
3 *
4 * FIXME: This file needs a description here.
5 *
6 * Copyright (c) 2001-2002 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * A. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * B. Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * C. Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
22 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "real_encoder.h"
35
36 // This file has the setup and the encode process of making raw YUV frames into Real Media streams.
37
38 BOOL g_bErrorOccurred = FALSE;
39 PN_RESULT g_nError = PNR_OK;
40
41
42 // This is the Tcl declaration, so that it is a registered Tcl class. Basically it just calls the RealWindow constructor.
43 static class RealWindowClass : public TclClass {
44 public:
45 RealWindowClass() : TclClass ("RealWindow") {};
46 TclObject* create(int argc, const char*const* argv) {
47 int wantVideo=FALSE, wantAudio=FALSE, wantSureStream=FALSE;
48 char* savefilename;
49 char* datarate;
50
51 if (atoi(argv[11]) != 0) {
52 savefilename = (char*)argv[12];
53 } else
54 savefilename = "";
55
56 if (strcmp(argv[16],"A/V") == 0) {
57 wantVideo = TRUE;
58 wantAudio = TRUE;
59 } else if (strcmp(argv[16],"A") == 0)
60 wantAudio = TRUE;
61 else
62 wantVideo = TRUE;
63
64 if (strncmp(argv[10],"SS",2) == 0)
65 wantSureStream = TRUE;
66
67 if (wantSureStream)
68 datarate = (char*)(&((argv[10])[2]));
69 else
70 datarate = (char*)argv[10];
71
72 return (new RealWindow(argv[4],argv[5],argv[6],argv[7],atoi(argv[8]),atoi(argv[9]),datarate,atoi(argv[11]),savefilename,argv[13],argv[14],argv[15], wantAudio,wantVideo,wantSureStream));
73 };
74 } realWindow;
75
76 // This is to catch the exceptions within the Real SDK
77 class CMyErrorSink : public IRMAErrorSink
78 {
79 public:
80 static PN_RESULT CreateInstance(IUnknown **pUnk);
81
82 STDMETHOD(QueryInterface) (THIS_ REFIID riid, void** ppvObj);
83 STDMETHOD_(ULONG32,AddRef) (THIS);
84 STDMETHOD_(ULONG32,Release) (THIS);
85
86 STDMETHOD(ErrorOccurred) (THIS_
87 const UINT8 unSeverity,
88 const ULONG32 ulRMACode,
89 const ULONG32 ulUserCode,
90 const char* pUserString,
91 const char* pMoreInfoURL
92 );
93
94 protected:
95 UINT32 m_nRefCount;
96
97 CMyErrorSink();
98 virtual ~CMyErrorSink();
99 };
100
101 // This is a helper function to get the current time in its correct form (ms).
102 ULONG32 GetTime()
103 {
104 // using a local nFirstTime prevents overflow when multiplying
105 // by 1000
106 static BOOL bFirst = TRUE;
107 static struct timeval start;
108
109 struct timeval now;
110
111 if(bFirst)
112 {
113 bFirst = FALSE;
114 gettimeofday(&start, NULL);
115 }
116
117 gettimeofday(&now, NULL);
118
119 ULONG32 sec = now.tv_sec - start.tv_sec;
120 ULONG32 usec = 0;
121
122 if(now.tv_usec < start.tv_usec)
123 {
124 // there will be overflow when subtracting
125 sec--;
126 usec = now.tv_usec + (1000000 - start.tv_usec);
127 }
128 else
129 usec = now.tv_usec - start.tv_usec;
130
131 return sec * 1000 + usec / 1000;
132 }
133
134 // This is the constructor for the Real Transcoder.
135 RealWindow::RealWindow(const char* given_server, const char* given_filename, const char* given_username, const char* given_password, int port, int frame_rate, const char* given_data_rate, int given_save_file, const char* given_local_file_name, const char* given_title, const char* given_author, const char* given_copyright, int audio, int video, int surestr): res(PNR_OK), pBuildEngine(NULL), pSample(NULL), cVideoFormat_Width(0), cVideoFormat_Height(0), cVideoFormat_FrameRate(frame_rate), cAudioFormat_SampleRate(8000), cAudioFormat_NumChannels(1), cAudioFormat_BitsPerSample(16), nSuggestedAudioBufferSize(0), pAudioPin(NULL), pVideoPin(NULL), nAudioTimestamp(0), nSystemTimestamp(0), colorModel(0),nextIn(0), nextOut(0), portNum(port), save_file(given_save_file), useAudio(audio), useVideo(video), sureStream(surestr) {
136 strcpy(server, given_server);
137 strcpy(filename, given_filename);
138 strcpy(username, given_username);
139 strcpy(password, given_password);
140 strcpy(data_rate, given_data_rate);
141 strcpy(local_file_name, given_local_file_name);
142 strcpy(title, given_title);
143 strcpy(author, given_author);
144 strcpy(copyright, given_copyright);
145
146 }
147
148 void RealWindow::setup_encoder() {
149 nBufferSize = cVideoFormat_Width*cVideoFormat_Height*3/2;
150 translate_frame = new u_int8_t[nBufferSize];
151
152 //////////////////////////////////////////////////////////
153 //
154 // Initialize the DLL locations before you call any
155 // functions in the RealProducer Core SDK
156 //
157 //////////////////////////////////////////////////////////
158
159 if(SUCCEEDED(res))
160 {
161 // Before you can call into the Build Engine DLL, you must
162 // initialize the DLL paths so that the Build Engine will
163 // know where to locate its required
164 // DLLs when you create your first Build Engine
165
166 printf("Setting up DLL paths\n");
167
168 // Create a null delimited, double-null terminated string containing
169 // DLL category name/path pairs. In this sample, we use the same
170 // directory for all DLLs (the current directory). You can split
171 // up the DLLs into different directories by category if you wish.
172 char szDllPath[2048];
173 UINT32 ulNumChars = 0;
174
175 char cwd[4096];
176 // getcwd(cwd, 2048);
177 bzero(cwd, 4096);
178 strcat(cwd, getenv("MASH_HOME"));
179 strcat(cwd, "/../realproducersdk/bin");
180 printf("path to DLLs is: %s\n", cwd);
181
182 ulNumChars += sprintf(szDllPath+ulNumChars,
183 "%s=%s", "DT_Plugins", cwd) + 1;
184 ulNumChars += sprintf(szDllPath+ulNumChars,
185 "%s=%s", "DT_Codecs", cwd) + 1;
186 ulNumChars += sprintf(szDllPath+ulNumChars,
187 "%s=%s", "DT_EncSDK", cwd) + 1;
188 ulNumChars += sprintf(szDllPath+ulNumChars,
189 "%s=%s", "DT_Common", cwd) + 1;
190 // terminator
191 //ulNumChars += sprintf(szDllPath+ulNumChars, "") + 1;
192
193 // Now that we have created the path, we hand it to the build engine
194 // by using the exported SetDLLAccessPath function.
195
196 res = SetDLLAccessPath(szDllPath);
197 }
198
199 //////////////////////////////////////////////////////////
200 //
201 // Create the build engine object itself
202 //
203 //////////////////////////////////////////////////////////
204
205 if(SUCCEEDED(res))
206 {
207 printf("creating build engine\n");
208
209 res = RMACreateRMBuildEngine(&pBuildEngine);
210 } else {
211 printf("The path to the DLLs is incorrect or some are missing\n");
212 exit(1);
213 }
214
215 //////////////////////////////////////////////////////////
216 //
217 // Enumerate the pins, and get the audio and video pins
218 //
219 //////////////////////////////////////////////////////////
220
221 if(SUCCEEDED(res))
222 {
223 IUnknown* tempUnk = NULL;
224 IRMAEnumeratorIUnknown* pPinEnum = NULL;
225
226 // get the pin enumerator
227
228 res = pBuildEngine->GetPinEnumerator(&pPinEnum);
229 assert(SUCCEEDED(res));
230
231 // enumerate the pins.
232
233 PN_RESULT resEnum = PNR_OK;
234 resEnum = pPinEnum->First(&tempUnk);
235
236 char* outputTypeStr = new char[ENC_MAX_STR];
237 while(SUCCEEDED(res) &&
238 SUCCEEDED(resEnum) &&
239 resEnum != PNR_ELEMENT_NOT_FOUND)
240 {
241 IRMAInputPin* tempPin = NULL;
242 res = tempUnk->QueryInterface(IID_IRMAInputPin, (void**)&tempPin);
243 PN_RELEASE(tempUnk);
244
245 if(SUCCEEDED(res))
246 res = tempPin->GetOutputMimeType(outputTypeStr, ENC_MAX_STR);
247
248 if(SUCCEEDED(res))
249 {
250 if(strcmp(outputTypeStr, MIME_REALAUDIO) == 0)
251 {
252 // save this pin in pAudioPin
253 pAudioPin = tempPin;
254 // addref it because we are going to use it later
255 pAudioPin->AddRef();
256 }
257 else if(strcmp(outputTypeStr, MIME_REALVIDEO) == 0)
258 {
259 // save this pin in pVideoPin
260 pVideoPin = tempPin;
261 // addref it because we are going to use it later
262 pVideoPin->AddRef();
263 }
264
265 printf("getting next pin\n");
266
267 PN_RELEASE(tempPin);
268 resEnum = pPinEnum->Next(&tempUnk);
269 }
270 else
271 {
272 printf("Cannot query input pin interface.\n");
273 }
274 }
275 delete [] outputTypeStr;
276
277 PN_RELEASE(pPinEnum);
278 } else {
279 printf("couldn't set up the build engine!\n");
280 exit(1);
281 }
282
283 //////////////////////////////////////////////////////////
284 //
285 // create the media sample object that we will use to
286 // pass data to the pins
287 //
288 //////////////////////////////////////////////////////////
289
290 if(SUCCEEDED(res))
291 {
292 printf("Creating a Media Sample\n");
293
294 IRMABuildClassFactory* pClassFactory = NULL;
295
296 res = pBuildEngine->QueryInterface(IID_IRMABuildClassFactory,
297 (void**)&pClassFactory);
298
299 if(SUCCEEDED(res))
300 {
301 // create an instance of class IRMAMediaSample
302
303 res = pClassFactory->CreateInstance(CLSID_IRMAMediaSample,
304 NULL, IID_IRMAMediaSample,
305 (void **)&pSample);
306 }
307
308 PN_RELEASE(pClassFactory);
309 }
310
311 //////////////////////////////////////////////////////////
312 //
313 // Setup the build engine main properties
314 //
315 //////////////////////////////////////////////////////////
316
317 if(SUCCEEDED(res))
318 {
319 //
320 // Do audio and video, but no events, or image maps
321 //
322
323 if (SUCCEEDED(res))
324 res = pBuildEngine->SetDoOutputMimeType(MIME_REALAUDIO, useAudio);
325
326 if(SUCCEEDED(res))
327 res = pBuildEngine->SetDoOutputMimeType(MIME_REALVIDEO, useVideo);
328
329 if(SUCCEEDED(res))
330 res = pBuildEngine->SetDoOutputMimeType(MIME_REALEVENT, FALSE);
331
332 if(SUCCEEDED(res))
333 res = pBuildEngine->SetDoOutputMimeType(MIME_REALIMAGEMAP, FALSE);
334
335 //
336 // for live capture, we must encode in realtime.
337 //
338
339 if(SUCCEEDED(res))
340 res = pBuildEngine->SetRealTimeEncoding(TRUE);
341
342 //
343 // We will create a surestream file. Set this to FALSE for a
344 // single rate file for web servers.
345 //
346 // With this set to TRUE, the build engine will generate multiple
347 // streams even though we have selected only one target audience.
348 // The extra streams are duress streams for low-bandwidth conditions.
349 //
350
351 if(SUCCEEDED(res))
352 res = pBuildEngine->SetDoMultiRateEncoding(sureStream);
353 }
354
355 //////////////////////////////////////////////////////////
356 //
357 // Setup main clip properties. This configures what
358 // we will output to: in this case to a server and
359 // a static file [live archiving]
360 //
361 // Also, we set up title, author, copyright, etc...
362 //
363 //////////////////////////////////////////////////////////
364
365 if(SUCCEEDED(res))
366 {
367 IRMAClipProperties* pClipProps = NULL;
368
369 //
370 // get the clip properties object
371 //
372
373 res = pBuildEngine->GetClipProperties(&pClipProps);
374
375 //
376 // we want to create a file
377 //
378
379 if(SUCCEEDED(res)) {
380 if (save_file > 0) {
381 res = pClipProps->SetDoOutputFile(TRUE);
382 // here is the filename we want to create
383 if(SUCCEEDED(res))
384 res = pClipProps->SetOutputFilename(local_file_name);
385 }
386 else
387 res = pClipProps->SetDoOutputFile(FALSE);
388 }
389 //
390 // we do not want to stream live to a server
391 //
392
393 if(SUCCEEDED(res)) {
394 if (save_file < 2) {
395 res = pClipProps->SetDoOutputServer(TRUE);
396 if(SUCCEEDED(res))
397 res = pClipProps->SetOutputServerInfo(server,filename,portNum,username,password);
398 if(SUCCEEDED(res))
399 printf("Connected successfully to the server\n");
400 }
401 else
402 res = pClipProps->SetDoOutputServer(FALSE);
403 }
404
405 //
406 // here is the server we want to stream to, and the
407 // name of the file on that server. If the server
408 // is set up in the standard way, then you can play
409 // it with this url in the player:
410
411
412 //
413 // title, author, etc...
414 //
415
416 if(SUCCEEDED(res))
417 res = pClipProps->SetTitle(title);
418 if(SUCCEEDED(res))
419 res = pClipProps->SetAuthor(author);
420 if(SUCCEEDED(res))
421 res = pClipProps->SetCopyright(copyright);
422
423
424 PN_RELEASE(pClipProps);
425 }
426
427 //////////////////////////////////////////////////////////
428 //
429 // Select some target audiences, and other settings
430 // related to how things are encoded.
431 //
432 //////////////////////////////////////////////////////////
433
434 if(SUCCEEDED(res))
435 {
436 IRMABasicTargetSettings* pBasicSettings = NULL;
437 IRMATargetSettings *pTargSettings = NULL;
438
439
440 //
441 // Build Engine returns a TargetSettings object,
442 // we must query for BasicTargetSettings
443 //
444
445 res = pBuildEngine->GetTargetSettings(&pTargSettings);
446
447 if(SUCCEEDED(res))
448 res = pTargSettings->QueryInterface(IID_IRMABasicTargetSettings,
449 (void**)&pBasicSettings);
450 PN_RELEASE(pTargSettings);
451
452 //
453 // reset the target audiences
454 //
455
456 if(SUCCEEDED(res))
457 res = pBasicSettings->RemoveAllTargetAudiences();
458
459 //
460 // set data rate
461 //
462
463 if(SUCCEEDED(res)) {
464 char* temp_data_rate = data_rate;
465 while (strncmp(temp_data_rate, "", 1) != 0) {
466 if ((strncmp(temp_data_rate,"56,",3)) == 0) {
467 res = pBasicSettings->AddTargetAudience(ENC_TARGET_56_MODEM);
468 temp_data_rate+=3;
469 printf("added target audience of 56K\n");
470 } else if ((strncmp(temp_data_rate,"128,",4)) == 0) {
471 res = pBasicSettings->AddTargetAudience(ENC_TARGET_DUAL_ISDN);
472 temp_data_rate+=4;
473 printf("added target audience of 128K\n");
474 } else if ((strncmp(temp_data_rate,"256,",4)) == 0) {
475 res = pBasicSettings->AddTargetAudience(ENC_TARGET_256_DSL_CABLE);
476 temp_data_rate+=4;
477 printf("added target audience of 256K\n");
478 } else if ((strncmp(temp_data_rate,"512,",4)) == 0) {
479 res = pBasicSettings->AddTargetAudience(ENC_TARGET_512_DSL_CABLE);
480 temp_data_rate+=4;
481 printf("added target audience of 512K\n");
482 } else {
483 if (TRUE /*see if valid data_rate */) {
484 printf("trying to enter personal data_rate\n");
485 } else
486 printf("invalid data_rate\n");
487 }
488 }
489 }
490
491 //
492 // select audio optimized for content containing mostly music
493 //
494
495 if(SUCCEEDED(res) && useAudio)
496 res = pBasicSettings->SetAudioContent(ENC_AUDIO_CONTENT_VOICE);
497
498 //
499 // select video optimized for normal content
500 //
501
502 if(SUCCEEDED(res) && useVideo)
503 res = pBasicSettings->SetVideoQuality(ENC_VIDEO_QUALITY_NORMAL);
504
505 //
506 // we want to be compatible with G2 [6.0] players or later
507 //
508
509 if(SUCCEEDED(res))
510 res = pBasicSettings->SetPlayerCompatibility(6);
511
512 PN_RELEASE(pBasicSettings);
513 }
514
515 //////////////////////////////////////////////////////////
516 //
517 // Setup the audio format on the audio pin
518 //
519 //////////////////////////////////////////////////////////
520
521 if(SUCCEEDED(res) && useAudio) {
522 IRMAPinProperties* pPinProps = NULL;
523 IRMAAudioPinProperties* pAudioPinProps = NULL;
524
525 res = pAudioPin->GetPinProperties(&pPinProps);
526
527 if(SUCCEEDED(res))
528 res = pPinProps->QueryInterface(IID_IRMAAudioPinProperties,
529 (void**)&pAudioPinProps);
530
531 PN_RELEASE(pPinProps);
532
533 //
534 // Here, we configure the audio pin with the format
535 // of the data that we will be passing to it.
536 // These constants are defined at the top of this file.
537 //
538
539 if(SUCCEEDED(res))
540 res = pAudioPinProps->SetSampleRate(cAudioFormat_SampleRate);
541
542 if(SUCCEEDED(res))
543 res = pAudioPinProps->SetNumChannels(cAudioFormat_NumChannels);
544
545 if(SUCCEEDED(res))
546 res = pAudioPinProps->SetSampleSize(cAudioFormat_BitsPerSample);
547
548 }
549
550 //////////////////////////////////////////////////////////
551 //
552 // Setup the video format on the video pin
553 //
554 //////////////////////////////////////////////////////////
555
556 if(SUCCEEDED(res) && useVideo)
557 {
558 IRMAPinProperties* pPinProps = NULL;
559 IRMAVideoPinProperties* pVideoPinProps = NULL;
560
561 res = pVideoPin->GetPinProperties(&pPinProps);
562
563 if(SUCCEEDED(res))
564 res = pPinProps->QueryInterface(IID_IRMAVideoPinProperties,
565 (void**)&pVideoPinProps);
566
567 PN_RELEASE(pPinProps);
568
569 //
570 // Here, we configure the video pin with the video size and frame
571 // rate, and video format. This is the format in which we will
572 // be providing video to the Encode() call.
573 //
574
575 if(SUCCEEDED(res))
576 res = pVideoPinProps->SetFrameRate(cVideoFormat_FrameRate);
577
578 if(SUCCEEDED(res))
579 res = pVideoPinProps->SetVideoSize(
580 cVideoFormat_Width,
581 cVideoFormat_Height);
582
583 if(SUCCEEDED(res))
584 res = pVideoPinProps->SetVideoFormat(ENC_VIDEO_FORMAT_I420);
585 }
586
587 // Do some Advanced Target Settings
588 /* if (SUCCEEDED(res) && (data_rate == 512)) {
589 IRMABuildClassFactory* pClassFactory = NULL;
590 IRMATargetAudienceManager* pTargetAudMgr = NULL;
591 IRMATargetAudienceInfo* pTargetInfo = NULL;
592 IRMACodecInfoManager* pCodecInfoMgr = NULL;
593 IUnknown* pCodecEnumTmp = NULL;
594 IRMAEnumeratorIUnknown* pCodecEnum = NULL;
595 IUnknown* tempUnk = NULL;
596 IRMACodecInfo* tempCodec = NULL;
597 PNCODECCOOKIE videoCodecToUse;
598 PNCODECCOOKIE audioCodecToUse;
599
600 res = pBuildEngine->QueryInterface(IID_IRMABuildClassFactory,
601 (void**)&pClassFactory);
602 if (SUCCEEDED(res)) {
603 res = pClassFactory->CreateInstance(CLSID_IRMATargetAudienceManager,
604 NULL, IID_IRMATargetAudienceManager, (void **)&pTargetAudMgr);
605 }
606 if (SUCCEEDED(res)) {
607 res = pClassFactory->CreateInstance(CLSID_IRMACodecInfoManager, NULL,
608 IID_IRMACodecInfoManager, (void **)&pCodecInfoMgr);
609 }
610 if (SUCCEEDED(res)) {
611 char codecName[100];
612 UINT32 codecCount;
613 PN_RESULT resEnum = PNR_OK;
614
615 res = pCodecInfoMgr->GetVideoCodecEnum(pCodecEnumTmp);
616 pCodecEnumTmp->QueryInterface(IID_IRMAEnumeratorIUnknown,
617 (void**)&pCodecEnum);
618 res = pCodecEnum->GetCount(&codecCount);
619 //printf("There are %d video codecs available\n", (int)codecCount);
620 resEnum = pCodecEnum->First(&tempUnk);
621 for(; codecCount > 0; codecCount--) {
622 res = tempUnk->QueryInterface(IID_IRMACodecInfo, (void**)&tempCodec);
623 tempCodec->GetCodecName(codecName, 100);
624 //printf("video codec name is %s\n", codecName);
625 if (strcmp(codecName, "RealVideo G2 with SVT") == 0) {
626 tempCodec->GetCodecCookie(videoCodecToUse);
627 printf("set video codec\n");
628 }
629 bzero(codecName, 100);
630 PN_RELEASE(tempCodec);
631 PN_RELEASE(tempUnk);
632 resEnum = pCodecEnum->Next(&tempUnk);
633 }
634 PN_RELEASE(pCodecEnumTmp);
635 PN_RELEASE(pCodecEnum);
636 PN_RELEASE(tempUnk);
637 res = pCodecInfoMgr->GetAudioCodecEnum(pCodecEnumTmp);
638 pCodecEnumTmp->QueryInterface(IID_IRMAEnumeratorIUnknown,
639 (void**)&pCodecEnum);
640 res = pCodecEnum->GetCount(&codecCount);
641 //printf("There are %d audio codecs available\n", (int)codecCount);
642 resEnum = pCodecEnum->First(&tempUnk);
643 for(; codecCount > 0; codecCount--) {
644 res = tempUnk->QueryInterface(IID_IRMACodecInfo, (void**)&tempCodec);
645 tempCodec->GetCodecName(codecName, 100);
646 //printf("audio codec name is %s\n", codecName);
647 if (strcmp(codecName, "16 Kbps Voice") == 0) {
648 tempCodec->GetCodecCookie(audioCodecToUse);
649 printf("set audio codec\n");
650 }
651 bzero(codecName, 100);
652 PN_RELEASE(tempCodec);
653 PN_RELEASE(tempUnk);
654 resEnum = pCodecEnum->Next(&tempUnk);
655 }
656 }
657 if (SUCCEEDED(res)) {
658 res = pTargetAudMgr->GetTargetAudienceInfo(ENC_TARGET_512_DSL_CABLE, pTargetInfo);
659 }
660 if (SUCCEEDED(res)) {
661 res = pTargetInfo->SetVideoCodec(videoCodecToUse);
662 res = pTargetInfo->SetAudioCodec(ENC_TARGET_AUDIENCES_VIDEO,
663 ENC_AUDIO_CONTENT_VOICE, audioCodecToUse);
664 res = pTargetInfo->SetTargetBitrate(1024);
665 res = pTargetInfo->SetMaxFrameRate(30);
666 }
667
668 PN_RELEASE(pClassFactory);
669 PN_RELEASE(pTargetAudMgr);
670 PN_RELEASE(pTargetInfo);
671 PN_RELEASE(pCodecInfoMgr);
672 PN_RELEASE(pCodecEnumTmp);
673 PN_RELEASE(pCodecEnum);
674 PN_RELEASE(tempUnk);
675 } */
676
677
678 //////////////////////////////////////////////////////////
679 //
680 // Prepare the build engine for encoding
681 //
682 //////////////////////////////////////////////////////////
683
684 if(SUCCEEDED(res))
685 {
686 printf("calling PrepareToEncode()\n");
687
688 res = pBuildEngine->PrepareToEncode();
689 }
690
691 //////////////////////////////////////////////////////////
692 //
693 // The Build Engine will recommend a size for audio
694 // buffers. You should pass buffers of this size
695 // into the audio pin
696 //
697 //////////////////////////////////////////////////////////
698
699 if(SUCCEEDED(res) && useAudio)
700 {
701 UINT32 nSize = 0;
702
703 IRMAAudioInputPin *pAudioSpecificPin = NULL;
704
705 res = pAudioPin->QueryInterface(IID_IRMAAudioInputPin,
706 (void **)&pAudioSpecificPin);
707
708 if(SUCCEEDED(res))
709 res = pAudioSpecificPin->GetSuggestedInputSize(&nSize);
710
711 if(SUCCEEDED(res))
712 {
713 nSuggestedAudioBufferSize = nSize;
714 printf("Suggested Audio Buffer Size is %d\n", (int)nSize);
715 // 8bits per byte*1000ms per sec*160bytes per sample / obvious stuff.
716 nAudioBufferDuration = (8*1000*nSuggestedAudioBufferSize)/(cAudioFormat_SampleRate*cAudioFormat_NumChannels*cAudioFormat_BitsPerSample);
717 }
718
719 PN_RELEASE(pAudioSpecificPin);
720 }
721
722 //////////////////////////////////////////////////////////
723 //
724 // Register our error sink
725 //
726 //////////////////////////////////////////////////////////
727
728 if(SUCCEEDED(res))
729 {
730 IUnknown *pMyErrorSinkObject = NULL;
731 IRMAErrorSink *pErrorSink = NULL;
732 IRMAErrorSinkControl *pErrorSinkControl = NULL;
733
734 res = CMyErrorSink::CreateInstance(&pMyErrorSinkObject);
735
736 if(SUCCEEDED(res))
737 {
738 printf("ErrorSink: getting from MyErrorSink object\n");
739
740 res = pMyErrorSinkObject->QueryInterface(IID_IRMAErrorSink,
741 (void **)&pErrorSink);
742 }
743
744 if(SUCCEEDED(res))
745 {
746 printf("ErrorSink: getting from Build Engine\n");
747
748 res = pBuildEngine->QueryInterface(IID_IRMAErrorSinkControl,
749 (void **)&pErrorSinkControl);
750 }
751
752 if(SUCCEEDED(res))
753 {
754 printf("ErrorSink: adding error sink\n");
755
756 res = pErrorSinkControl->AddErrorSink(pErrorSink,
757 PNLOG_EMERG, PNLOG_INFO);
758 }
759 printf("ErrorSink: done, res = 0x%08x\n", (uint) res);
760
761 PN_RELEASE(pErrorSink);
762 PN_RELEASE(pErrorSinkControl);
763 PN_RELEASE(pMyErrorSinkObject);
764 }
765 }
766
767 void RealWindow::planar422toI420(char* dest, char* src) {
768 int width = cVideoFormat_Width/2;
769 int height = cVideoFormat_Height/2;
770 int size = cVideoFormat_Width * cVideoFormat_Height;
771
772 memcpy(dest, src, size);
773 src = src + size;
774 dest = dest + size;
775
776 for (int i = 0; i < height; i++) {
777 memcpy(dest+(i*width),src+(2*i*width), width);
778 }
779
780 dest = dest + (width*height);
781 src = src + (width*2*height);
782 for (int i = 0; i < height; i++) {
783 memcpy(dest+(i*width),src+(2*i*width), width);
784 }
785 }
786
787 void RealWindow::recv(Buffer* buffer) {
788 u_int8_t* in_frame_ = ((YuvFrame*)buffer)->bp_;
789 ULONG32 nVideoTimestamp;
790
791 if (!useVideo)
792 return;
793
794 // When capturing live data, you must pass it to the build
795 // engine interleaved.
796 //
797
798 if (cVideoFormat_Width == 0) {
799 cVideoFormat_Width = ((YuvFrame*)buffer)->width_;
800 cVideoFormat_Height = ((YuvFrame*)buffer)->height_;
801 setup_encoder();
802 }
803
804 // need to translate formats if it is a JPEG
805 if (colorModel == 422) {
806 planar422toI420((char*)translate_frame, (char*)in_frame_);
807 in_frame_ = translate_frame;
808 }
809
810 //////////////////////////////////////////////////////////
811 //
812 // Encode!
813 //
814 // This sends interleaved audio and video packets
815 // to the build engine. In this sample app, we use
816 // our random a/v generator to create random a/v packets.
817 // Replace this with code to read your source data.
818 //
819 //////////////////////////////////////////////////////////
820
821 if(SUCCEEDED(res)) {
822 nVideoTimestamp = GetTime();
823 if (useAudio) {
824 nVideoTimestamp = (nVideoTimestamp - nSystemTimestamp) + nAudioTimestamp;
825 if (nAudioTimestamp == 0)
826 return;
827 }
828 // put the data into our IRMAMediaSample so that
829 // we can encode it. Note: calling SetBuffer()
830 // stores a pointer to the buffer you give -- it
831 // does not copy it. So keep the buffer around
832 // until you have called Encode().
833 //
834 // printf("sending video frame at %d\n", (int)nVideoTimestamp);
835
836 if(SUCCEEDED(res))
837 res = pSample->SetBuffer(
838 in_frame_,
839 nBufferSize,
840 nVideoTimestamp,
841 0);
842
843 //
844 // Encode it!
845 //
846 if(SUCCEEDED(res))
847 res = pVideoPin->Encode(pSample);
848
849 //
850 // Very important: if there is an asynchronous error
851 // while encoding, our CMyErrorSink object will have
852 // set g_bErrorOccurred. If this happened, we need
853 // to stop encoding. So we set our 'res' variable
854 // to the error that occurred and this will break
855 // our while loop.
856 //
857
858 if(SUCCEEDED(res) && g_bErrorOccurred)
859 {
860 res = g_nError;
861 }
862 } else {
863 printf("can't encode video block due to earlier error\n");
864 }
865 }
866
867 void RealWindow::encodeAudio(u_short* buf, int size, ULONG32 now) {
868 //printf("got a chunk of audio\n");
869 if(!useAudio)
870 return;
871
872 if(SUCCEEDED(res)) {
873 //nTimestamp = GetTime();
874 /* if(SUCCEEDED(res))
875 printf("time=%6d: %s buffer (size=%d)\n",
876 nTimestamp,
877 bIsAudio?"audio":"video",
878 nBufferSize); */
879
880 //
881 // put the data into our IRMAMediaSample so that
882 // we can encode it. Note: calling SetBuffer()
883 // stores a pointer to the buffer you give -- it
884 // does not copy it. So keep the buffer around
885 // until you have called Encode().
886 //
887
888 nAudioTimestamp += nAudioBufferDuration;
889 nSystemTimestamp = now;
890
891 // printf("sending audio frame at %d\n", (int)nAudioTimestamp);
892
893 if(SUCCEEDED(res))
894 res = pSample->SetBuffer(
895 buf,
896 size,//nSuggestedAudioBufferSize,
897 nAudioTimestamp,
898 // might be 1 if this is a sync point
899 0);
900
901 //
902 // Encode it!
903 //
904 if(SUCCEEDED(res))
905 res = pAudioPin->Encode(pSample);
906
907 //
908 // Very important: if there is an asynchronous error
909 // while encoding, our CMyErrorSink object will have
910 // set g_bErrorOccurred. If this happened, we need
911 // to stop encoding. So we set our 'res' variable
912 // to the error that occurred and this will break
913 // our while loop.
914 //
915
916 if(SUCCEEDED(res) && g_bErrorOccurred)
917 {
918 res = g_nError;
919 }
920 } else {
921 printf("can't encode audio block due to earlier error\n");
922 }
923 }
924
925 int RealWindow::command(int argc, const char*const* argv) {
926 if (argc == 3) {
927 if (strcmp(argv[1], "setColorModel") == 0) {
928 colorModel = atoi(argv[2]);
929 return (TCL_OK);
930 }
931 }
932 return (Renderer::command(argc,argv));
933 }
934
935 //////////////////////////////////////////////////////////
936 //
937 // We are done encoding -- cleanup
938 //
939 //////////////////////////////////////////////////////////
940 RealWindow::~RealWindow() {
941 if(SUCCEEDED(res))
942 {
943 printf("calling DoneEncoding()\n");
944
945 res = pBuildEngine->DoneEncoding();
946 }
947
948 PN_RELEASE(pAudioPin);
949 PN_RELEASE(pVideoPin);
950 PN_RELEASE(pSample);
951 PN_RELEASE(pBuildEngine);
952
953 printf("Done Encoding, res = 0x%08x\n", (uint)res);
954
955 printf("Done, res = 0x%08x\n", (uint)res);
956 }
957
958 ///////////////////////
959 // Error Sink stuff ///
960 ///////////////////////
961
962 PN_RESULT CMyErrorSink::CreateInstance(IUnknown **ppUnk)
963 {
964 CMyErrorSink *pObj = new CMyErrorSink();
965
966 if(pObj == NULL)
967 {
968 *ppUnk = NULL;
969 return PNR_OUTOFMEMORY;
970 }
971 else
972 {
973 *ppUnk = (IUnknown*)pObj;
974 (*ppUnk)->AddRef();
975 return PNR_OK;
976 }
977 }
978
979 CMyErrorSink::CMyErrorSink()
980 : m_nRefCount(0)
981 {
982 }
983
984 CMyErrorSink::~CMyErrorSink()
985 {
986 }
987
988 STDMETHODIMP CMyErrorSink::QueryInterface(REFIID riid, void** ppvObj)
989 {
990 if(!ppvObj)
991 return PNR_POINTER;
992 else if(IsEqualIID(IID_IUnknown, riid))
993 {
994 AddRef();
995 *ppvObj = (IUnknown*)this;
996 return PNR_OK;
997 }
998 else if(IsEqualIID(IID_IRMAErrorSink, riid))
999 {
1000 AddRef();
1001 *ppvObj = (IRMAErrorSink*)this;
1002 return PNR_OK;
1003 }
1004
1005 *ppvObj = NULL;
1006 return PNR_NOINTERFACE;
1007 }
1008
1009 ULONG32 CMyErrorSink::AddRef()
1010 {
1011 return InterlockedIncrement(&m_nRefCount);
1012 }
1013
1014 ULONG32 CMyErrorSink::Release()
1015 {
1016 if(InterlockedDecrement(&m_nRefCount) > 0)
1017 return m_nRefCount;
1018
1019 delete this;
1020 return 0;
1021 }
1022
1023 STDMETHODIMP CMyErrorSink::ErrorOccurred(const UINT8 unSeverity,
1024 const ULONG32 ulRMACode,
1025 const ULONG32 ulUserCode,
1026 const char* pUserString,
1027 const char* pMoreInfoURL
1028 )
1029 {
1030 printf("ERROR OCCURRED: "
1031 "sev=%d, err=0x%08x, usercode=%d, "
1032 "string=\"%s\", moreinfo=\"%s\"\n",
1033 unSeverity,
1034 (uint)ulRMACode,
1035 (int)ulUserCode,
1036 pUserString,
1037 pMoreInfoURL);
1038
1039 if(unSeverity <= PNLOG_ERR)
1040 {
1041 g_bErrorOccurred = TRUE;
1042 g_nError = ulRMACode;
1043 }
1044 return PNR_OK;
1045 }
1046
1047
1048
1049
1050
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.