I am trying to compile Qt with Intel icpc on Ubuntu 14.04 and I get a compilation error on this file - qpnghandler.cpp
From the qpnghandler.cpp file that I have this is the relevant code -
static
void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, float screen_gamma=0.0)
{
if (screen_gamma != 0.0 && png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
double file_gamma;
png_get_gAMA(png_ptr, info_ptr, &file_gamma);
png_set_gamma(png_ptr, screen_gamma, file_gamma);
}
png_uint_32 width;
png_uint_32 height;
int bit_depth;
int color_type;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
if (color_type == PNG_COLOR_TYPE_GRAY) {
// Black & White or 8-bit grayscale
if (bit_depth == 1 && info_ptr->channels == 1) {
png_set_invert_mono(png_ptr);
png_read_update_info(png_ptr, info_ptr);
if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) {
image = QImage(width, height, QImage::Format_Mono);
if (image.isNull())
return;
}
image.setColorCount(2);
image.setColor(1, qRgb(0,0,0));
image.setColor(0, qRgb(255,255,255));
} else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_expand(png_ptr);
png_set_strip_16(png_ptr);
png_set_gray_to_rgb(png_ptr);
if (image.size() != QSize(width, height) || image.format() != QImage::Format_ARGB32) {
image = QImage(width, height, QImage::Format_ARGB32);
if (image.isNull())
return;
}
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
png_set_swap_alpha(png_ptr);
png_read_update_info(png_ptr, info_ptr);
} else {
if (bit_depth == 16)
png_set_strip_16(png_ptr);
else if (bit_depth < 8)
png_set_packing(png_ptr);
int ncols = bit_depth < 8 ? 1 << bit_depth : 256;
png_read_update_info(png_ptr, info_ptr);
if (image.size() != QSize(width, height) || image.format() != QImage::Format_Indexed8) {
image = QImage(width, height, QImage::Format_Indexed8);
if (image.isNull())
return;
}
image.setColorCount(ncols);
for (int i=0; i<ncols; i++) {
int c = i*255/(ncols-1);
image.setColor(i, qRgba(c,c,c,0xff));
}
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
#if PNG_LIBPNG_VER_MAJOR < 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 4)
const int g = info_ptr->trans_values.gray;
#else
const int g = info_ptr->trans_color.gray;
#endif
if (g < ncols) {
image.setColor(g, 0);
}
}
}
} else if (color_type == PNG_COLOR_TYPE_PALETTE
&& png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)
&& info_ptr->num_palette <= 256)
{
// 1-bit and 8-bit color
if (bit_depth != 1)
png_set_packing(png_ptr);
png_read_update_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
QImage::Format format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8;
if (image.size() != QSize(width, height) || image.format() != format) {
image = QImage(width, height, format);
if (image.isNull())
return;
}
image.setColorCount(info_ptr->num_palette);
int i = 0;
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
while (i < info_ptr->num_trans) {
image.setColor(i, qRgba(
info_ptr->palette[i].red,
info_ptr->palette[i].green,
info_ptr->palette[i].blue,
#if PNG_LIBPNG_VER_MAJOR < 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 4)
info_ptr->trans[i]
#else
info_ptr->trans_alpha[i]
#endif
)
);
i++;
}
}
while (i < info_ptr->num_palette) {
image.setColor(i, qRgba(
info_ptr->palette[i].red,
info_ptr->palette[i].green,
info_ptr->palette[i].blue,
0xff
)
);
i++;
}
} else {
// 32-bit
if (bit_depth == 16)
png_set_strip_16(png_ptr);
png_set_expand(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
QImage::Format format = QImage::Format_ARGB32;
// Only add filler if no alpha, or we can get 5 channel data.
if (!(color_type & PNG_COLOR_MASK_ALPHA)
&& !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_filler(png_ptr, 0xff, QSysInfo::ByteOrder == QSysInfo::BigEndian ?
PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
// We want 4 bytes, but it isn't an alpha channel
format = QImage::Format_RGB32;
}
if (image.size() != QSize(width, height) || image.format() != format) {
image = QImage(width, height, format);
if (image.isNull())
return;
}
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
png_set_swap_alpha(png_ptr);
png_read_update_info(png_ptr, info_ptr);
}
// Qt==ARGB==Big(ARGB)==Little(BGRA)
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
png_set_bgr(png_ptr);
}
}
Can somebody guide me on what modifications I can bring to that file so that I can compile qpnghandler.cpp ?
icpc -c -wd654,1572 -g -pthread -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -O2 -fvisibility=hidden -fvisibility-inlines-hidden -D_REENTRANT -I/usr/include/freetype2 -fPIC -DQT_SHARED -DQT_BUILD_GUI_LIB -DQT_NO_USING_NAMESPACE -DQT_NO_CAST_TO_ASCII -DQT_ASCII_CAST_WARNINGS -DQT3_SUPPORT -DQT_MOC_COMPAT -DQT_HAVE_MMX -DQT_HAVE_SSE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_NO_OPENTYPE -DQT_NO_STYLE_MAC -DQT_NO_STYLE_WINDOWSVISTA -DQT_NO_STYLE_WINDOWSXP -DQT_NO_STYLE_WINDOWSCE -DQT_NO_STYLE_WINDOWSMOBILE -DQT_NO_STYLE_S60 -DQ_INTERNAL_QAPP_SRC -DQT_NO_DEBUG -DQT_CORE_LIB -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I../../mkspecs/linux-icc -I. -I../../include/QtCore -I../../include -I../../include/QtGui -I.rcc/release-shared -I../3rdparty/xorg -I/usr/include/freetype2 -I../3rdparty/harfbuzz/src -Idialogs -I.moc/release-shared -I/usr/X11R6/include -I.uic/release-shared -o .obj/release-shared/qpnghandler.o image/qpnghandler.cpp
image/qpnghandler.cpp(169): error: pointer to incomplete class type is not allowed
if (bit_depth == 1 && info_ptr->channels == 1) {
^
image/qpnghandler.cpp(214): error: pointer to incomplete class type is not allowed
const int g = info_ptr->trans_color.gray;
^
image/qpnghandler.cpp(223): error: pointer to incomplete class type is not allowed
&& info_ptr->num_palette <= 256)
^
image/qpnghandler.cpp(236): error: pointer to incomplete class type is not allowed
image.setColorCount(info_ptr->num_palette);
^
image/qpnghandler.cpp(239): error: pointer to incomplete class type is not allowed
while (i < info_ptr->num_trans) {
^
image/qpnghandler.cpp(241): error: pointer to incomplete class type is not allowed
info_ptr->palette[i].red,
^
image/qpnghandler.cpp(242): error: pointer to incomplete class type is not allowed
info_ptr->palette[i].green,
^
TL;DR: you're compiling an ancient Qt against a new libpng. This new libpng has changed its API in an incompatible way. Newer Qt supports this newer libpng just fine.
Qt 4.6 was released in 2009. If you're for some reason stuck with Qt 4.x, you should definitely use the 4.8 branch -- because it contains security and portability fixes like the one which solves the problem that you're hitting. However, upstream support for the 4.x branch of Qt has ended, so you should probably look into porting your code to Qt 5.x if you're actively working on this project (and if you expect to continue working on it in future).
If you desperately want to create a Frankenstein build of Qt 4.6 for some reason (maybe you're bisecting a tricky error in Qt 4 and want to reach back seven years into the history to see if that version was buggy, too), you should look into using the 1.4 branch of libpng. If that is not possible for you for some reason, then you can carefully port the Qt's PNG code to the API of libpng-1.5 or libpng-1.6. Details on how to do this are available at libpng 1.5.10 error: dereferencing pointer to incomplete type.
Related
I am encoding video with h264 codec and mp4 container. The source is a sequence of images I load from memory. The encoding seems to be working good. I am able to verify the exact amount of frames encoded, but what bugs me is the following warning/error I am getting at the end of the session from the muxer in terminal:
Application provided invalid, non monotonically increasing dts to
muxer in stream 0:
I tried different techniques to calculate pts/dts and it is the same. I did notice though, that avcodec_receive_packet() sometimes returns packets out of order,so may be that's the reason for the warning? Below is my function where I encode the image data.
bool LibAVEncoder::EncodeFrame(uint8_t* data)
{
int err;
if (!mVideoFrame)//init frame once
{
mVideoFrame = av_frame_alloc();
mVideoFrame->format = mVideoStream->codecpar->format;
mVideoFrame->width = mCodecContext->width;
mVideoFrame->height = mCodecContext->height;
if ((err = av_frame_get_buffer(mVideoFrame, 0)) < 0)
{
printf("Failed to allocate picture: %i\n", err);
return false;
}
}
err = av_frame_make_writable(mVideoFrame);
if (!mSwsCtx)
{
mSwsCtx = sws_getContext(mCodecContext->width, mCodecContext->height, AV_PIX_FMT_RGBA, mCodecContext->width,
mCodecContext->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, 0, 0, 0);
}
const int inLinesize[1] = { 4 * mCodecContext->width };
// RGBA to YUV
sws_scale(mSwsCtx, (const uint8_t* const*)&data, inLinesize, 0, mCodecContext->height, mVideoFrame->data, mVideoFrame->linesize);
mVideoFrame->pts = mFrameCount++;
//Encoding
err = avcodec_send_frame(mCodecContext, mVideoFrame);
if (err < 0)
{
printf("Failed to send frame: %i\n", err);
return false;
}
while (err >= 0)
{
err = avcodec_receive_packet(mCodecContext, mPacket);
if (err == AVERROR(EAGAIN))
{
return true;
}
else if (err == AVERROR_EOF)
{
return true;
}
else if (err < 0)
{
fprintf(stderr, "Error during encoding,shutting down\n");
exit(1);
}
// 1. way of calc pts/dts
mPacket->pts = av_rescale_q_rnd(mPacket->pts, mCodecContext->time_base, mVideoStream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
mPacket->dts = av_rescale_q_rnd(mPacket->dts, mCodecContext->time_base, mVideoStream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
mPacket->duration = av_rescale_q(mPacket->duration, mCodecContext->time_base, mVideoStream->time_base);
/*
//2. another way of calc pts/dts
const int64_t duration = av_rescale_q(1, mCodecContext->time_base, mVideoStream->time_base);
mPacket->duration = duration;
mPacket->pts = totalDuration;
mPacket->dts = totalDuration;
totalDuration += duration;
*/
mPacket->stream_index = mVideoStream->index;
av_interleaved_write_frame(mOFormatContext, mPacket);
av_packet_unref(mPacket);
}
return true;
}
I would appreciate any pointer to what I am doing wrong here.
When I try to open a font, I always get NULL in return and TTL_GetError doesn't provide any error message.
I use SDL2 (v2.0.9.0) and the SDL_TTF (v2.0.15) under Windows.
Code Snippets:
SDL/TTF Init:
bool Graphics::Init()
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("[SDL]\tInitialization error: %s\n",SDL_GetError());
return false;
}
mWindowFlags |= SDL_WINDOW_SHOWN;
if (SCREEN_FULLSCREEN) mWindowFlags |= SDL_WINDOW_FULLSCREEN;
if (SCREEN_BORDERLESS) mWindowFlags |= SDL_WINDOW_BORDERLESS;
mWindow = SDL_CreateWindow("Titel", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, mWindowFlags);
if (mWindow == NULL)
{
printf("[SDL]\tWindow creation error: %s\n", SDL_GetError());
return false;
}
mRenderer = SDL_CreateRenderer(mWindow, -1, SDL_RENDERER_ACCELERATED);
if (mRenderer == NULL)
{
printf("[SDL]\tRenderer creation error: %s\n", SDL_GetError());
return false;
}
SDL_SetRenderDrawColor(mRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
// Flags for image format handle
int flags = IMG_INIT_PNG;
if (!(IMG_Init(flags) & flags))
{
printf("[SDL IMG]\tInitialization error: %s\n", IMG_GetError());
return false;
}
if (TTF_Init() != 0)
{
printf("[SDL TTF]\tInitialization error: %s\n",TTF_GetError());
return false;
}
mBackBuffer = SDL_GetWindowSurface(mWindow);
return true;
}
TTF Font:
TTF_Font * AssetManager::GetFont(std::string filename, int size)
{
std::string fullpath = SDL_GetBasePath();
fullpath.append("Assets\\Fonts\\" + filename);
std::string key = fullpath + (char)size;
if (mFonts[key] == nullptr)
{
mFonts[key] == TTF_OpenFont(fullpath.c_str(), size);
if (mFonts[key] == nullptr)
{
printf("[SDL TTF]\tFont loading error: Font:(%s) | FPath:(%s) | Error:(%s)\n",filename.c_str(), fullpath.c_str(), TTF_GetError());
}
}
return mFonts[key];
}
Output:
I tried already different TTF fonts but with no success.
If I give him a not existing font, I get a normal error that it couldnt get loaded.
Have somebody any idea or had a similar problems ?
Good morning.
Now, H.264 packet is received from the camera with FFMpeg and decoding succeeded.
And I want to output the decoded data to the screen, but it does not work well.
(We successfully saved the decoded data in PPM, Bitmap file, and the screen was well saved.)
Here is the Source code.
CameraStream.cpp
void CameraStream::Play(CWnd *view)
{
m_View = view;
m_StreamThread = std::thread{
[&, this]()
{
AVPacket packet;
int i = 0;
while (true)
{
{
std::unique_lock<std::mutex> threadMux(this->m_StreamMux);
if (!m_IsStreamAlive)
{
MessageBox(nullptr, _T("ThreadOut"), nullptr, MB_OK);
break;
}
}
int err = av_read_frame(this->m_FormatContext, &packet);
if (err < 0)
{
break;
}
if (packet.stream_index == m_VideoStreamIdx)
{
err = avcodec_send_packet(this->m_VideoCondecContext, &packet);
if (err < 0
|| err == AVERROR(EAGAIN)
|| err == AVERROR_EOF)
{
break;
}
CDC *dc = ((CNetworkVideoViewerView*)m_View)->GetDC();
BYTE *pbmpdata = nullptr;
BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biHeight = -(m_VideoCondecContext->height);
bmi.bmiHeader.biWidth = m_VideoCondecContext->width;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biSizeImage = m_VideoCondecContext->height * m_VideoCondecContext->width * 3;
HBITMAP hbmp = CreateDIBSection(dc->GetSafeHdc(), &bmi, DIB_RGB_COLORS, (void**)&pbmpdata, NULL, 0);
AVFrame *frame = av_frame_alloc();;
AVFrame *frameRGB = av_frame_alloc();
uint8_t *buffer = nullptr;
int numBytes = 0;
numBytes = av_image_get_buffer_size(
AV_PIX_FMT_BGR24,
this->m_VideoCondecContext->width,
this->m_VideoCondecContext->height,
1);
buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
int err = av_image_fill_arrays(
frameRGB->data,
frameRGB->linesize,
(uint8_t*)pbmpdata, // Bitmap Pointer
//buffer,
AV_PIX_FMT_BGR24,
this->m_VideoCondecContext->width,
this->m_VideoCondecContext->height,
1);
if (err < 0)
{
break;
}
SwsContext *swsContext = nullptr;
swsContext = sws_getContext(
this->m_VideoCondecContext->width,
this->m_VideoCondecContext->height,
this->m_VideoCondecContext->pix_fmt,
this->m_VideoCondecContext->width,
this->m_VideoCondecContext->height,
AV_PIX_FMT_BGR24,
SWS_BICUBIC,
nullptr,
nullptr,
nullptr);
if (!swsContext)
{
return false;
}
while (err >= 0)
{
err = avcodec_receive_frame(this->m_VideoCondecContext, frame);
if (err == AVERROR(EAGAIN)
|| err == AVERROR(EINVAL)
|| err == AVERROR_EOF)
{
break;
}
if (frame->pkt_size != 0)
{
sws_scale(
swsContext,
(const uint8_t * const *)frame->data,
frame->linesize,
0,
this->m_VideoCondecContext->height,
frameRGB->data,
frameRGB->linesize);
// SendMessage Main Thread.
((CNetworkVideoViewerView*)(m_View))->SendMessage(
UM_DISPLAYBITMAP,
(WPARAM)hbmp);
}
}
av_frame_free(&frame);
av_frame_free(&frameRGB);
sws_freeContext(swsContext);
av_free((void*)buffer);
((CNetworkVideoViewerView*)m_View)->ReleaseDC(dc);
}
av_packet_unref(&packet);
};
} };
};
NetWorkViewerView.cpp
// UM_DISPLAYBITMAP
afx_msg LRESULT CNetworkVideoViewerView::OnUmDisplaybitmap(WPARAM wParam, LPARAM lParam)
{
HBITMAP *hBmp = (HBITMAP*)wParam;
CDC *dc = GetDC();
CDC memDC;
memDC.CreateCompatibleDC(dc);
BITMAP bmpInfo;
GetObject(hBmp, sizeof(BITMAP), &bmpInfo);
memDC.SelectObject(hBmp);
dc->BitBlt(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCCOPY);
DeleteObject(hBmp);
ReleaseDC(dc);
return 0;
}
The above source runs normally without error, but only the black screen is displayed on the application screen.
Why is it created as a bitmap file but not the bitmap you want to display on the screen?
Thank you in advance.
[ 2018. 01. 10 Solved ]
I modified the source as you suggested, and FFmpeg replaces the buffer space with a bitmap address so the screen looks good.
Of course, there are still some areas that need to be fixed, but the screen looks good. Thank you.
I recently started experimenting with the DirectShow Examples of the BlackMagic SDK.
I made my first application but I experienced some strange behaviour when reading the available Video modes of the Card (a DeckLink Studio 4K).
Sidenote: same behaviour happens on Windows 7 Prof. & HP x64 and Win 8.1 Pro x64.
My Problem is, that I am not getting Video modes like 25p, 29.97p and 30p.
Although the capture device is capable of them, even more they work perfectly with Blackmagic Media Express.
HRESULT CDecklinkCaptureDlg::PopulateVideoControl()
{
HRESULT hr = S_OK;
if (m_pVideoCapture)
{
int count = m_videoFormatCtrl.GetCount();
if (count)
{
for (int item=0; item<count; ++item)
{
DeleteMediaType((AM_MEDIA_TYPE*)m_videoFormatCtrl.GetItemData(item));
}
m_videoFormatCtrl.ResetContent();
}
CComPtr<IAMStreamConfig> pISC = NULL;
hr = CDSUtils::FindPinInterface(m_pVideoCapture, &MEDIATYPE_Video, PINDIR_OUTPUT, IID_IAMStreamConfig, reinterpret_cast<void**>(&pISC));
if (SUCCEEDED(hr))
{
int count, size;
hr = pISC->GetNumberOfCapabilities(&count, &size);
if (SUCCEEDED(hr))
{
if (sizeof(VIDEO_STREAM_CONFIG_CAPS) == size)
{
AM_MEDIA_TYPE* pmt = NULL;
VIDEO_STREAM_CONFIG_CAPS vscc;
VIDEOINFOHEADER* pvih = NULL;
for (int index=0; index<count; ++index)
{
hr = pISC->GetStreamCaps(index, &pmt, reinterpret_cast<BYTE*>(&vscc));
if (SUCCEEDED(hr))
{
TCHAR buffer[128];
float frameRate;
char* pixelFormatString;
ZeroMemory(buffer, sizeof(buffer));
pvih = (VIDEOINFOHEADER*)pmt->pbFormat;
//
if (pvih->bmiHeader.biBitCount == 16)
pixelFormatString = TEXT("8 bit 4:2:2 YUV");
else if (pvih->bmiHeader.biBitCount == 20)
pixelFormatString = TEXT("10 bit 4:2:2 YUV");
else if (pvih->bmiHeader.biBitCount == 30)
pixelFormatString = TEXT("10 bit 4:4:4 RGB");
else
pixelFormatString = TEXT("");
if (486 == pvih->bmiHeader.biHeight)
{
if (417083 == pvih->AvgTimePerFrame)
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("NTSC - %s (3:2 pulldown removal)"), pixelFormatString);
}
else
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("NTSC - %s"), pixelFormatString);
}
}
else if (576 == pvih->bmiHeader.biHeight)
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("PAL - %s"), pixelFormatString);
}
else
{
frameRate = (float)UNITS / pvih->AvgTimePerFrame;
if (720 == pvih->bmiHeader.biHeight)
{
// 720p
if ((frameRate - (int)frameRate) > 0.01)
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("HD 720p %.2f - %s"), frameRate, pixelFormatString);
}
else
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("HD 720p %.0f - %s"), frameRate, pixelFormatString);
}
}
else if (1080 == pvih->bmiHeader.biHeight)
{
if ((frameRate < 25) || (frameRate >= 50.0)) // 1080p23, 1080p24, 1080p50, 1080p5994, 1080p60
{
// Progressive 1080
if ((frameRate - (int)frameRate) > 0.01)
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("HD 1080p %.2f - %s"), frameRate, pixelFormatString);
}
else
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("HD 1080p %.0f - %s"), frameRate, pixelFormatString);
}
}
else
{
// Interlaced 1080
if ((frameRate - (int)frameRate) > 0.01)
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("HD 1080i %.2f - %s"), frameRate*2.0f, pixelFormatString);
}
else
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("HD 1080i %.0f - %s"), frameRate*2.0f, pixelFormatString);
}
}
}
else if (1556 == pvih->bmiHeader.biHeight)
{
if ((frameRate - (int)frameRate) > 0.01)
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("2K 1556p %.2f - %s"), frameRate, pixelFormatString);
}
else
{
StringCbPrintf(buffer, sizeof(buffer), TEXT("2K 1556p %.0f - %s"), frameRate, pixelFormatString);
}
}
}
// If the display mode was recognized, add it to the listbox UI
if (buffer[0] != 0)
{
// add the item description to combo box
int n = m_videoFormatCtrl.AddString(buffer);
// store media type pointer in item's data section
m_videoFormatCtrl.SetItemData(n, (DWORD_PTR)pmt);
// set default format
if ((pvih->AvgTimePerFrame == m_vihDefault.AvgTimePerFrame) &&
(pvih->bmiHeader.biWidth == m_vihDefault.bmiHeader.biWidth) &&
(pvih->bmiHeader.biHeight == m_vihDefault.bmiHeader.biHeight) &&
(pvih->bmiHeader.biBitCount == m_vihDefault.bmiHeader.biBitCount))
{
m_videoFormatCtrl.SetCurSel(n);
pISC->SetFormat(pmt);
}
}
else
{
DeleteMediaType(pmt);
}
}
}
}
else
{
m_videoFormatCtrl.AddString(TEXT("ERROR: Unable to retrieve video formats"));
}
}
}
// as the device is being changed, update the IDecklinkInputStatus interface
{
CAutoLock lock(&m_csInputStatusLock); // prevent thread from using this interface while it is changed
m_pIDecklinkStatus = m_pVideoCapture;
if (m_pIDecklinkStatus)
{
m_pIDecklinkStatus->RegisterVideoStatusChangeEvent((unsigned long)m_hInputStatusChangeEvent);
}
}
}
else
{
hr = E_POINTER;
}
return hr;
}
Now of course i tried changing this:
"if ((frameRate < 25) || (frameRate >= 50.0))"
to
"if ((frameRate < 30) || (frameRate >= 50.0))"
But that just renames the 1080 50i / 59,94i / 60i to 25p / 29.97p / 30p.
I doesn't give me the ability to use 30p, it just is renamed as 30p but captures still 60i.
Maybe someone more experienced can figure out the Problem. I think it has something to do with DirectShow interpresing i.e. 59.94i as a framerate of 29.97 and so it can't populate that framerate twice.
Thanks in advance (and sorry for any misspells -> from Germany),
Marco
Blackmagic offers their SDK as a primary API and then their DirectShow filters are built on top of this SDK. That is, DirectShow filters offer a subset of SDK functionality, and this is where in particular you see issues with interlaced/progressive media type overlap (their filters don't do interlaced capture in terms of delivering video feed with truely interlaced media type, or by fields), you are basically limited to what the filter makes available.
I recently solved the Bitmap problem in my last post. Now I'm back with another Image problem. This time it's PNG.
I'm using LibPng to read and write PNG files. I have a struct that holds BGRA information of each Pixel. I know that the pixels are stored up right and in RGBA format. So I specified swapping of the B and the R. That works fine. I think I'm somehow flipping the image but I'm not quite sure.
My problem comes in when I try to convert 24 bit PNG to 32 bit PNG and vice-versa. Currently, I can do 24 to 24 and 32 to 32 just fine.
Can you guys look over my code and tell me what I'm doing wrong when attempting to convert from 24 to 32?
The below code works for loading and writing the same PNG back to the disk. I made sure to include everything in this one file so that you guys can compile it and see if necessary.
#include <iostream>
#include <vector>
#include <fstream>
#include <stdexcept>
#include "Libraries/LibPng/Include/png.h"
typedef union RGB
{
uint32_t Color;
struct
{
unsigned char B, G, R, A;
} RGBA;
} *PRGB;
std::vector<RGB> Pixels;
uint32_t BitsPerPixel, width, height;
int bitdepth, colortype, interlacetype, channels;
void ReadFromStream(png_structp PngPointer, png_bytep Data, png_size_t Length) //For reading using ifstream rather than FILE*
{
std::ifstream *Stream = (std::ifstream*)png_get_io_ptr(PngPointer);
Stream->read((char*)Data, Length);
}
void WriteToStream(png_structp PngPointer, png_bytep Data, png_size_t Length) //For writing using ofstream rather than FILE*
{
std::ofstream *Stream = (std::ofstream*)png_get_io_ptr(PngPointer);
Stream->write((char*)Data, Length);
}
void Load(const char* FilePath)
{
std::fstream hFile(FilePath, std::ios::in | std::ios::binary);
if (!hFile.is_open()){throw std::invalid_argument("File Not Found.");}
unsigned char Header[8] = {0};
hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header));
if (png_sig_cmp(Header, 0, 8))
{
hFile.close();
throw std::invalid_argument("Error: Invalid File Format. Required: Png.");
}
png_structp PngPointer = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!PngPointer)
{
hFile.close();
throw std::runtime_error("Error: Cannot Create Read Structure.");
}
png_infop InfoPointer = png_create_info_struct(PngPointer);
if (!InfoPointer)
{
hFile.close();
png_destroy_read_struct(&PngPointer, nullptr, nullptr);
throw std::runtime_error("Error: Cannot Create InfoPointer Structure.");
}
png_infop EndInfo = png_create_info_struct(PngPointer);
if (!EndInfo)
{
hFile.close();
png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr);
throw std::runtime_error("Error: Cannot Create EndInfo Structure.");
}
if (setjmp(png_jmpbuf(PngPointer)))
{
hFile.close();
png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr);
throw std::runtime_error("Error: Cannot Set Jump Pointer.");
}
png_set_sig_bytes(PngPointer, sizeof(Header));
png_set_read_fn(PngPointer, reinterpret_cast<void*>(&hFile), ReadFromStream);
png_read_info(PngPointer, InfoPointer);
//This is where I start getting the info and storing it..
channels = png_get_channels(PngPointer, InfoPointer);
png_get_IHDR(PngPointer, InfoPointer, &width, &height, &bitdepth, &colortype, &interlacetype, nullptr, nullptr);
png_set_strip_16(PngPointer);
png_set_packing(PngPointer);
switch (colortype)
{
case PNG_COLOR_TYPE_GRAY:
{
png_set_expand(PngPointer);
break;
}
case PNG_COLOR_TYPE_GRAY_ALPHA:
{
png_set_gray_to_rgb(PngPointer);
break;
}
case PNG_COLOR_TYPE_RGB:
{
png_set_bgr(PngPointer);
BitsPerPixel = 24;
break;
}
case PNG_COLOR_TYPE_RGBA:
{
png_set_bgr(PngPointer);
BitsPerPixel = 32;
break;
}
default: png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr); throw std::runtime_error("Error: Png Type not supported."); break;
}
//Store the new data.
png_read_update_info(PngPointer, InfoPointer);
channels = png_get_channels(PngPointer, InfoPointer);
png_get_IHDR(PngPointer, InfoPointer, &width, &height, &bitdepth, &colortype, &interlacetype, nullptr, nullptr);
Pixels.resize(width * height);
std::vector<unsigned char*> RowPointers(height);
unsigned char* BuffPos = reinterpret_cast<unsigned char*>(Pixels.data());
//Set the row pointers to my Pixels vector. This way, the image is stored upright in my vector<BGRA> Pixels.
//I think this is flipping it for some reason :S
for (size_t I = 0; I < height; ++I)
{
RowPointers[I] = BuffPos + (I * width * ((BitsPerPixel > 24) ? 4 : 3));
}
png_read_image(PngPointer, RowPointers.data()); //Get the pixels as BGRA and store it in my struct vector.
png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr);
hFile.close();
std::cout<<"Loading Parameters..."<<std::endl;
std::cout<<"Bits: "<<BitsPerPixel<<std::endl;
std::cout<<"Depth: "<<bitdepth<<std::endl;
std::cout<<"CType: "<<colortype<<std::endl;
}
void Save(const char* FilePath)
{
std::fstream hFile(FilePath, std::ios::out | std::ios::binary);
if (!hFile.is_open()) {throw std::invalid_argument("Cannot open file for writing.");}
png_structp PngPointer = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!PngPointer)
{
hFile.close();
throw std::runtime_error("Error: Cannot Create Write Structure.");
}
png_infop InfoPointer = png_create_info_struct(PngPointer);
if (!InfoPointer)
{
hFile.close();
png_destroy_write_struct(&PngPointer, nullptr);
throw std::runtime_error("Error: Cannot Create InfoPointer Structure.");
}
if (setjmp(png_jmpbuf(PngPointer)))
{
hFile.close();
png_destroy_write_struct(&PngPointer, &InfoPointer);
throw std::runtime_error("Error: Cannot Set Jump Pointer.");
}
std::cout<<"\nSaving Parameters..."<<std::endl;
std::cout<<"Bits: "<<BitsPerPixel<<std::endl;
std::cout<<"Depth: "<<bitdepth<<std::endl;
std::cout<<"CType: "<<colortype<<std::endl;
//This is where I set all the Information..
png_set_IHDR (PngPointer, InfoPointer, width, height, bitdepth, BitsPerPixel == 24 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
std::vector<unsigned char*> RowPointers(height);
unsigned char* BuffPos = reinterpret_cast<unsigned char*>(Pixels.data());
//Set the Row pointers to my vector<BGRA> Pixels. It should have been stored upright already.
//I think this flips it upside down :S?
for (size_t I = 0; I < height; ++I)
{
RowPointers[I] = BuffPos + (I * width * ((BitsPerPixel > 24) ? 4 : 3));
}
png_set_bgr(PngPointer); //My struct vector holds BGRA and PNG requires RGBA so swap them..
png_set_write_fn(PngPointer, reinterpret_cast<void*>(&hFile), WriteToStream, nullptr);
png_set_rows(PngPointer, InfoPointer, RowPointers.data());
png_write_png(PngPointer, InfoPointer, PNG_TRANSFORM_IDENTITY, NULL);
png_destroy_write_struct(&PngPointer, &InfoPointer);
hFile.close();
}
void SetBitsPerPixel(uint32_t BPP)
{
BitsPerPixel = BPP;
bitdepth = (BPP > 24 ? 8 : 6);
channels = (BPP > 24 ? 4 : 3);
colortype = (BPP > 24 ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB);
}
int main()
{
Load("C:/Images/Png24.png");
SetBitsPerPixel(32);
Save("C:/Images/Output/Png32.png");
}
I load (24 bit PNG made with MS-Paint):
When I save it back as 24, it saves flawlessly. When I attempt to save it back as 32, it looks like:
Try doing the following modifications to your source code. Not tested!
In your Load function change this:
case PNG_COLOR_TYPE_RGB:
{
png_set_bgr(PngPointer);
BitsPerPixel = 24;
break;
}
to this:
case PNG_COLOR_TYPE_RGB:
{
png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER);
png_set_bgr(PngPointer);
BitsPerPixel = 32;
break;
}
In your Load and Save functions change this:
for (size_t I = 0; I < height; ++I)
{
RowPointers[I] = BuffPos + (I * width * ((BitsPerPixel > 24) ? 4 : 3));
}
to this:
size_t BytesPerLine = width << 2;
unsigned char *ptr = BuffPos;
for (size_t I = 0; I < height; ++I, ptr += BytesPerLine)
RowPointers[I] = ptr;
In your Save function change this:
png_write_png(PngPointer, InfoPointer, PNG_TRANSFORM_IDENTITY, NULL);
to this:
png_write_png(PngPointer, InfoPointer, BitsPerPixel == 24 ? PNG_TRANSFORM_STRIP_FILLER : PNG_TRANSFORM_IDENTITY, NULL);
and in your SetBitsPerPixel function change this line:
bitdepth = (BPP > 24 ? 8 : 6);
to this:
bitdepth = (BPP >= 24 ? 8 : 6);
Actually, I'm not sure why you're doing this, since, as far as I know, 24 and 32 bpp images should have a bitdepth of 8 bits.
NOTE: This modifications are intended for 24 and 32 bpp images, so if you want to use indexed or greyscale images you may need to do some extra modifications. The point is that you should always save pixels in a BGRA buffer (no matter if you load indexed, greyscale or RGB images with no alpha channel).