~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Open Mash Cross Reference
mash/tgw/real_encoder.cc

Component: ~ [ mash ] ~ [ apps ] ~ [ gsm ] ~ [ lib ] ~ [ otcl ] ~ [ srm ] ~ [ tcl8.3 ] ~ [ tclcl ] ~ [ tk8.3 ] ~ [ tutorials ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.