I have some trouble with my project. That is while I capture data from input video and playback video out to monitor. I see the error "couldn't schedule video frame"
I do this because I want to know data from input video to process this data and change color, add another picture to video and so on.
This is step-by-step which i did.
-create notification callback from input while input video change.
-create event callback when schedule video frame complete
-Enable video input
-Enable video output
-Create video frame. its just 1 frame
-Schedule video frame
-Start schedule video playback
while input video frame arrived which i created notification callback, i add input video frame to schedule video to playback.
I dont know why i had this error. It's notification when schedule video frame. Thanks. I wanna to know detail why I get this error and how to slove that.
- Code: Select all
#include "platform.h"
#include <iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
using namespace std;
using namespace cv;
Mat frame;
// Keep track of the number of scheduled frames
INT32_UNSIGNED gTotalFramesScheduled = 1;
const INT32_UNSIGNED kFrameDuration = 1000;
const INT32_UNSIGNED kTimeScale = 25000;
// Video mode parameters
const BMDDisplayMode kDisplayMode = bmdModeHD1080i50;
const BMDVideoOutputFlags kOutputFlag = bmdVideoOutputFlagDefault;
const BMDPixelFormat kPixelFormat = bmdFormat10BitYUV;
const INT32_UNSIGNED kFrameWidth = 1920;
const INT32_UNSIGNED kFrameHeight = 1080;
const INT32_UNSIGNED kRowBytes = 5120;
class OutputCallback : public IDeckLinkVideoOutputCallback
{
public:
OutputCallback(IDeckLinkOutput* deckLinkOutput)
{
m_deckLinkOutput = deckLinkOutput;
m_deckLinkOutput->AddRef();
}
virtual ~OutputCallback(void)
{
m_deckLinkOutput->Release();
}
HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result)
{
// When a video frame completes,reschedule another frame
m_deckLinkOutput->ScheduleVideoFrame(completedFrame, gTotalFramesScheduled*kFrameDuration, kFrameDuration, kTimeScale);
gTotalFramesScheduled++;
return S_OK;
}
HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped(void)
{
return S_OK;
}
// IUnknown needs only a dummy implementation
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv)
{
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return 1;
}
ULONG STDMETHODCALLTYPE Release()
{
return 1;
}
private:
IDeckLinkOutput* m_deckLinkOutput;
};
// The input callback class
class NotificationCallback : public IDeckLinkInputCallback
{
public:
IDeckLinkInput* m_deckLinkInput;
IDeckLinkOutput* m_deckLinkOutput;
NotificationCallback(IDeckLinkInput *deckLinkInput, IDeckLinkOutput *deckLinkOutput)
{
m_deckLinkInput = deckLinkInput;
m_deckLinkOutput = deckLinkOutput;
}
~NotificationCallback(void)
{
}
HRESULT STDMETHODCALLTYPE QueryInterface (REFIID iid, LPVOID *ppv)
{
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef ()
{
return 1;
}
ULONG STDMETHODCALLTYPE Release ()
{
return 1;
}
// The callback that is called when a property of the video input stream has changed.
HRESULT STDMETHODCALLTYPE VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags)
{
BMDPixelFormat pixelFormat = bmdFormat8BitBGRA;
STRINGOBJ displayModeString = NULL;
// Check for video field changes
if (notificationEvents & bmdVideoInputFieldDominanceChanged)
{
BMDFieldDominance fieldDominance;
fieldDominance = newDisplayMode->GetFieldDominance();
printf("Input field dominance changed to ");
switch (fieldDominance) {
case bmdUnknownFieldDominance:
printf("unknown\n");
break;
case bmdLowerFieldFirst:
printf("lower field first\n");
break;
case bmdUpperFieldFirst:
printf("upper field first\n");
break;
case bmdProgressiveFrame:
printf("progressive\n");
break;
case bmdProgressiveSegmentedFrame:
printf("progressive segmented frame\n");
break;
default:
break;
}
}
// Check if the pixel format has changed
if (notificationEvents & bmdVideoInputColorspaceChanged)
{
printf("Input color space changed to ");
if (detectedSignalFlags == bmdDetectedVideoInputYCbCr422)
{
printf("YCbCr422\n");
pixelFormat = bmdFormat8BitBGRA;
}
if (detectedSignalFlags == bmdDetectedVideoInputRGB444)
{
printf("RGB444\n");
pixelFormat = bmdFormat8BitBGRA;
}
}
// Check if the video mode has changed
if (notificationEvents & bmdVideoInputDisplayModeChanged)
{
std::string modeName;
// Obtain the name of the video mode
newDisplayMode->GetName(&displayModeString);
StringToStdString(displayModeString, modeName);
printf("Input display mode changed to: %s\n", modeName.c_str());
// Release the video mode name string
STRINGFREE(displayModeString);
}
// Pause video capture
//m_deckLinkInput->PauseStreams();
// Enable video input with the properties of the new video stream
//m_deckLinkInput->EnableVideoInput(newDisplayMode->GetDisplayMode(), pixelFormat, bmdVideoInputEnableFormatDetection);
// Flush any queued video frames
//m_deckLinkInput->FlushStreams();
// Start video capture
// m_deckLinkInput->StartStreams();
return S_OK;
}
HRESULT STDMETHODCALLTYPE VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket)
{
INT32_UNSIGNED* nextWord;
INT32_UNSIGNED wordsRemaining;
HRESULT result;
videoFrame->AddRef();
m_deckLinkOutput->Release();
videoFrame->GetBytes((void**)&nextWord);
wordsRemaining = ((int)videoFrame->GetRowBytes() * (int)videoFrame->GetHeight()) / 4;
while (wordsRemaining > 0)
{
*(nextWord++) = 0x40aa298;
wordsRemaining = wordsRemaining - 1;
}
result = m_deckLinkOutput->ScheduleVideoFrame(videoFrame, gTotalFramesScheduled*kFrameDuration, kFrameDuration, kTimeScale);
if (result != S_OK)
{
fprintf(stderr, "Could not schedule video frame - result = %08x\n", result);
goto bail;
}
gTotalFramesScheduled++;
bail:
videoFrame->Release();
return S_OK;
}
};
static void FillBlue(IDeckLinkMutableVideoFrame* theFrame)
{
INT32_UNSIGNED* nextWord;
INT32_UNSIGNED wordsRemaining;
theFrame->GetBytes((void**)&nextWord);
wordsRemaining = (kRowBytes * kFrameHeight) / 4;
while (wordsRemaining > 0)
{
*(nextWord++) = 0x40aa298;
wordsRemaining = wordsRemaining - 1;
}
}
static IDeckLinkMutableVideoFrame* CreateFrame(IDeckLinkOutput* deckLinkOutput)
{
HRESULT result;
IDeckLinkMutableVideoFrame* frame = NULL;
result = deckLinkOutput->CreateVideoFrame(kFrameWidth, kFrameHeight, kRowBytes, kPixelFormat, bmdFrameFlagDefault, &frame);
if (result != S_OK)
{
fprintf(stderr, "Could not create a video frame - result = %08x\n", result);
}
FillBlue(frame);
return frame;
}
int main (int argc, char** argv)
{
IDeckLinkIterator* deckLinkIterator = NULL;
IDeckLinkAttributes* deckLinkAttributes = NULL;
IDeckLink* deckLink = NULL;
IDeckLinkInput* deckLinkInput = NULL;
NotificationCallback* notificationCallback = NULL;
HRESULT result;
BOOL supported;
INT8_UNSIGNED returnCode = 1;
IDeckLinkOutput* deckLinkOutput = NULL;
OutputCallback* outputCallback = NULL;
IDeckLinkVideoFrame* videoFrameBlue = NULL;
Initialize();
// Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system
if (GetDeckLinkIterator(&deckLinkIterator) != S_OK)
{
fprintf(stderr, "A DeckLink iterator could not be created. The DeckLink drivers may not be installed.\n");
goto bail;
}
// Obtain the first DeckLink device
result = deckLinkIterator->Next(&deckLink);
if (result != S_OK)
{
fprintf(stderr, "Could not find DeckLink device - result = %08x\n", result);
goto bail;
}
// Obtain the Attributes interface for the DeckLink device
result = deckLink->QueryInterface(IID_IDeckLinkAttributes, (void**)&deckLinkAttributes);
if (result != S_OK)
{
fprintf(stderr, "Could not obtain the IDeckLinkAttributes interface - result = %08x\n", result);
goto bail;
}
// Determine whether the DeckLink device supports input format detection
result = deckLinkAttributes->GetFlag(BMDDeckLinkSupportsInputFormatDetection, &supported);
if ((result != S_OK) || (supported == false))
{
fprintf(stderr, "Device does not support automatic mode detection\n");
goto bail;
}
// Obtain the input interface for the DeckLink device
result = deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&deckLinkInput);
if (result != S_OK)
{
fprintf(stderr, "Could not obtain the IDeckLinkInput interface - result = %08x\n", result);
goto bail;
}
// Obtain the output interface for the DeckLink device
result = deckLink->QueryInterface(IID_IDeckLinkOutput, (void**)&deckLinkOutput);
if (result != S_OK)
{
fprintf(stderr, "Could not obtain the IDeckLinkInput interface - result = %08x\n", result);
goto bail;
}
// Create an instance of notification callback
notificationCallback = new NotificationCallback(deckLinkInput,deckLinkOutput);
if (notificationCallback == NULL)
{
fprintf(stderr, "Could not create notification callback object\n");
goto bail;
}
// Create an instance of output callback
outputCallback = new OutputCallback(deckLinkOutput);
if (outputCallback == NULL)
{
fprintf(stderr, "Could not create output callback object\n");
goto bail;
}
// Set the callback object to the DeckLink device's input interface
result = deckLinkInput->SetCallback(notificationCallback);
if (result != S_OK)
{
fprintf(stderr, "Could not set callback - result = %08x\n", result);
goto bail;
}
// Set the callback object to the DeckLink device's output interface
result = deckLinkOutput->SetScheduledFrameCompletionCallback(outputCallback);
if (result != S_OK)
{
fprintf(stderr, "Could not set callback - result = %08x\n", result);
goto bail;
}
// Enable video input with a default video mode and the automatic format detection feature enabled
result = deckLinkInput->EnableVideoInput(bmdModeHD1080i50, bmdFormat10BitYUV, bmdVideoInputFlagDefault);
if (result != S_OK)
{
fprintf(stderr, "Could not enable video input - result = %08x\n", result);
goto bail;
}
//printf("Starting streams\n");
// Start capture
//result = deckLinkInput->StartStreams();
//if (result != S_OK)
//{
// fprintf(stderr, "Could not start capture - result = %08x\n", result);
// goto bail;
//}
// Create a frame with defined format
videoFrameBlue = CreateFrame(deckLinkOutput);
result = deckLinkOutput->ScheduleVideoFrame(videoFrameBlue, gTotalFramesScheduled*kFrameDuration, kFrameDuration, kTimeScale);
if (result != S_OK)
{
fprintf(stderr, "Could not schedule video frame - result = %08x\n", result);
goto bail;
}
// Start
result = deckLinkOutput->StartScheduledPlayback(0, kTimeScale, 1.0);
if (result != S_OK)
{
fprintf(stderr, "Could not start - result = %08x\n", result);
goto bail;
}
printf("Monitoring... Press <RETURN> to exit\n");
getchar();
printf("Exiting.\n");
// Stop capture
result = deckLinkInput->StopStreams();
// Disable the video input interface
result = deckLinkInput->DisableVideoInput();
// Stop capture
result = deckLinkOutput->StopScheduledPlayback(0, NULL, 0);
// Disable the video input interface
result = deckLinkOutput->DisableVideoOutput();
// return success
returnCode = 0;
// Release resources
bail:
// Release the attributes interface
if(deckLinkAttributes != NULL)
deckLinkAttributes->Release();
// Release the video input interface
if(deckLinkInput != NULL)
deckLinkInput->Release();
// Release the video input interface
if (deckLinkOutput != NULL)
deckLinkOutput->Release();
// Release the Decklink object
if(deckLink != NULL)
deckLink->Release();
// Release the DeckLink iterator
if(deckLinkIterator != NULL)
deckLinkIterator->Release();
// Release the notification callback object
if(notificationCallback)
delete notificationCallback;
// Release the outputCallback callback object
if (outputCallback)
delete outputCallback;
getchar();
return returnCode;
}