I want to take images from my IP camera. I work in visual studio 2012.
At first, I've used openCV to connect to it. Here is my code.
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/opencv.hpp"
int main()
{
cv::VideoCapture vcap;
const std::string videoStreamAddress = "rtsp://admin:admin#192.168.0.120/snl/live/1/1/stream1.cgi";
if (!vcap.open(videoStreamAddress))
{
printf("camera is null\n");
return -1;
}
else
{
cv::Mat image;
cv::namedWindow("Video", CV_WINDOW_AUTOSIZE);
while(1)
{
vcap >> image;
imshow("Video", image);
if(cv::waitKey(10) == 99 ) break;
}
}
cv::waitKey(1000);
return 0;
}
It shows the stream. But some of its images have distortion. I think it is because of decoding error. The error is this:
[h264 # 00decfe0] error while decoding MB 37 22, bytestream <td>
To solve this error I write another code inspired from http://answers.opencv.org/question/65932/how-to-stream-h264-video-with-rtsp-in-opencv-partially-answered/ . It uses libVLC to get the stream. here is my second code.
#include "opencv2/opencv.hpp"
#include "vlc/libvlc.h"
#include "vlc/libvlc_media.h"
#include "vlc/libvlc_media_player.h"
#include "ctime"
#include "Windows.h"
#include "string"
struct ctx
{
IplImage* image;
HANDLE mutex;
uchar* pixels;
};
void *lock(void *data, void**p_pixels)
{
struct ctx *ctx = (struct ctx*)data;
WaitForSingleObject(ctx->mutex, INFINITE);
*p_pixels = ctx->pixels;
return NULL;
}
void display(void *data, void *id){
(void) data;
assert(id == NULL);
}
void unlock(void *data, void *id, void *const *p_pixels){
struct ctx *ctx = (struct ctx*)data;
/* VLC just rendered the video, but we can also render stuff */
uchar *pixels = (uchar*)*p_pixels;
cvShowImage("image", ctx->image);
ReleaseMutex(ctx->mutex);
assert(id == NULL); /* picture identifier, not needed here */
}
int main()
{
// VLC pointers
libvlc_instance_t *vlcInstance;
libvlc_media_player_t *mp;
libvlc_media_t *media;
const char * const vlc_args[] = {
"-I", "dummy", // Don't use any interface
"--ignore-config", // Don't use VLC's config
"--extraintf=logger", // Log anything
"--verbose=2", // Be much more verbose then normal for debugging purpose
};
vlcInstance = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
media = libvlc_media_new_location(vlcInstance, "rtsp://admin:admin#192.168.21.120/snl/live/1/1/stream1.cgi");
mp = libvlc_media_player_new_from_media(media);
libvlc_media_release(media);
context->mutex = CreateMutex(NULL, FALSE, NULL);
context->image = new Mat(VIDEO_HEIGHT, VIDEO_WIDTH, CV_8UC3);
context->pixels = (unsigned char *)context->image->data;
// show blank image
imshow("test", *context->image);
libvlc_video_set_callbacks(mp, lock, unlock, display, context);
libvlc_video_set_format(mp, "RV24", VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_WIDTH * 24 / 8); // pitch = width * BitsPerPixel / 8
int ii = 0;
int key = 0;
while(key != 27)
{
ii++;
if (ii > 5)
{
libvlc_media_player_play(mp);
}
float fps = libvlc_media_player_get_fps(mp);
//printf("fps:%f\r\n",fps);
key = waitKey(100); // wait 100ms for Esc key
}
libvlc_media_player_stop(mp);
return 0;
}
But it has nearly the same error. Some pixels losts and images has distortion.
[h264 # 02a3b660] Frame num gap 6 4
[h264 # 02a42220] no picture oooo
How Can I fix this problem? The problem rooted from my code and the using libraries or my camera?
im working on some project like you,this error is because openCVcant deal with H264 , i suggest you use VLC library as mentioned in here,and cause you use VS2012 you can use VLCDotNetin your project.other options is FFmpeg,aforgethat are compatible with H264.
Related
I'm working on an image drawing program and I'm getting really confused about colorspaces. The more I read about gamma, the less I know (this wasn't much help).
Internally, the drawing program will store images as 8-bit sRGB and then convert to 16-bit linear for compositing and filtering operations. Perhaps I should store 16-bit linear and then convert to 8-bit sRGB when exporting? I'd love some advice on this. Currently, I'm not really sure what colorspace the RGB pixels are being interpreted as by Qt!
As I understand it, sRGB is close to the colorspace that most monitors use so converting from sRGB to the monitor colorspace doesn't change the image data much. Looking at the sRGB data as if it were in the right colorspace will probably be pretty close.
Goals
The drawing program displays sRGB images. I want to save these sRGB images to a PNG file. When I open this PNG file (with Preview on a Mac) on the same computer that the image was created on, it should look exactly the same as what the artist sees in the drawing program and have the same color values (checked with Digital Color Meter). Different monitors and different operating systems use different colorspaces. These colorspaces might not "fit" the colorspace of the system used to create the image. When I open the PNG on a different monitor or even a different computer, the image should look as similar as possible to the original but probably have different color values.
Experiments
The drawing program seems to be displaying the images correctly (I think). The problem is the PNG. I'm using Qt and saving the image with QImage::save. I'm willing to use libPNG if I need more control.
For testing, I'm drawing a 5x5 image with the color values 0 63 127 191 255 for red and green.
Drawing program screenshots
When I sample the image rendered by the drawing program with Digital Color Meter, the pixel values are unchanged. The pixel at 3,3 sampled with DCM is 191 191 0 as it should be. There is a clear contrast between each of the pixels.
When I take a screenshot, the pixel values in the screenshot file are different. The pixel at 3,3 sampled with DCM when viewing in Preview is 192 191 0. The pixel at 3,3 stored in the file is 140 126 4. I should note that the screenshot file has an sRGB chunk with a rendering intent perceptual.
When I crop the screenshot to a 5x5 image using Preview, the sRGB chunk is replaced with the gAMA and cHRM chunks that correspond to sRGB (I used pngcheck).
gAMA
0.45455
cHRM
White x = 0.3127 y = 0.329, Red x = 0.64 y = 0.33
Green x = 0.3 y = 0.6, Blue x = 0.15 y = 0.06
Both versions have the same pixel values stored in the file. They also have the same pixel values when sampled with DCM when viewing in Preview.
Below is the cropped screenshot (it's really tiny!).
The best way of saving a drawing seems to be taking a screenshot but even that's not perfect.
Test programs
Qt program
#include <QtGui/qimage.h>
int main() {
QImage image{5, 5, QImage::Format_RGB32};
const int values[5] = {0, 63, 127, 191, 255};
for (int r = 0; r != 5; ++r) {
for (int g = 0; g != 5; ++g) {
image.setPixel(g, r, qRgb(values[r], values[g], 0));
}
}
image.save("qt.png");
}
This program produces the same output as the libpng program except that Qt adds a pHYs chunk. The output looks similar to the desired output but there is less contrast between the pixels and the pixel values are significantly off.
Libpng program
#include <cmath>
#include <iostream>
#include <libpng16/png.h>
png_byte srgb_lut[256];
void initLut(const double exponent) {
for (int i = 0; i != 256; ++i) {
srgb_lut[i] = std::round(std::pow(i / 255.0, exponent) * 255.0);
}
}
int main() {
std::FILE *file = std::fopen("libpng.png", "wb");
if (!file) {
std::cerr << "Failed to open file\n";
return 1;
}
png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!pngPtr) {
std::fclose(file);
std::cout << "Failed to initialize png write struct\n";
return 1;
}
png_infop infoPtr = png_create_info_struct(pngPtr);
if (!infoPtr) {
png_destroy_write_struct(&pngPtr, nullptr);
std::fclose(file);
std::cout << "Failed to initialize png info struct\n";
return 1;
}
if (setjmp(png_jmpbuf(pngPtr))) {
png_destroy_write_struct(&pngPtr, &infoPtr);
std::fclose(file);
std::cout << "Failed to set jmp buf\n";
return 1;
}
png_init_io(pngPtr, file);
png_set_IHDR(
pngPtr,
infoPtr,
5,
5,
8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT
);
//png_set_gAMA_fixed(pngPtr, infoPtr, 100000);
//png_set_sRGB_gAMA_and_cHRM(pngPtr, infoPtr, PNG_sRGB_INTENT_PERCEPTUAL);
//png_set_sRGB(pngPtr, infoPtr, PNG_sRGB_INTENT_PERCEPTUAL);
//initLut(2.2);
//initLut(1.0/2.2);
initLut(1.0);
png_bytep rows[5];
png_color imageData[5][5];
const png_byte values[5] = {0, 63, 127, 191, 255};
for (int r = 0; r != 5; ++r) {
for (int g = 0; g != 5; ++g) {
imageData[r][g] = {srgb_lut[values[r]], srgb_lut[values[g]], 0};
}
rows[r] = reinterpret_cast<png_bytep>(&imageData[r][0]);
}
png_set_rows(pngPtr, infoPtr, rows);
png_write_png(pngPtr, infoPtr, PNG_TRANSFORM_IDENTITY, nullptr);
png_destroy_write_struct(&pngPtr, &infoPtr);
std::fclose(file);
}
As I said the previous section, the output is similar to the desired output but there is reduced contrast. The pixel at 3,3 sampled with DCM when viewing in Preview is 186 198 0 which is way off.
I'm really glad that Qt is producing the same output as libpng even though the output isn't what I want it to be. It means that I could switch to libpng if I needed to.
Sample program
This program samples a pixel from a PNG. I'm pretty sure it doesn't do any color space conversion and just gives me the value stored in the file.
#include <iostream>
#include <libpng16/png.h>
int main(int argc, char **argv) {
if (argc != 4) {
std::cout << "sample <file> <x> <y>\n";
return 1;
}
const int x = std::atoi(argv[2]);
const int y = std::atoi(argv[3]);
if (x < 0 || y < 0) {
std::cerr << "Coordinates out of range\n";
return 1;
}
std::FILE *file = std::fopen(argv[1], "rb");
if (!file) {
std::cerr << "Failed to open file\n";
return 1;
}
png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!pngPtr) {
std::fclose(file);
std::cerr << "Failed to initialize read struct\n";
return 1;
}
png_infop infoPtr = png_create_info_struct(pngPtr);
if (!infoPtr) {
png_destroy_read_struct(&pngPtr, nullptr, nullptr);
std::fclose(file);
std::cerr << "Failed to initialize info struct\n";
return 1;
}
if (setjmp(png_jmpbuf(pngPtr))) {
// Pssh, who needs exceptions anyway?
png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);
std::fclose(file);
std::cerr << "Failed to set jmp buf\n";
return 1;
}
png_init_io(pngPtr, file);
// Does this prevent libpng from changing the color values?
png_set_gamma(pngPtr, PNG_GAMMA_LINEAR, PNG_GAMMA_LINEAR);
png_read_png(pngPtr, infoPtr, PNG_TRANSFORM_STRIP_ALPHA, nullptr);
png_bytepp rows = png_get_rows(pngPtr, infoPtr);
const int width = png_get_image_width(pngPtr, infoPtr);
const int height = png_get_image_height(pngPtr, infoPtr);
if (x >= width || y >= height) {
// Pssh, who needs RAII anyway?
png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);
std::fclose(file);
std::cerr << "Coordinates out of range\n";
return 1;
}
png_bytep row = rows[y];
for (int c = 0; c != 3; ++c) {
std::cout << static_cast<int>(row[x * 3 + c]) << ' ';
}
std::cout << '\n';
png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);
std::fclose(file);
}
What I'm really trying to do
I need to modify the libpng test program so that the pixel values are 0 63 127 191 255 when opened with Preview and sampled with Digital Color Meter. Sounds like a simple task but it most definitely isn't. There's some commented code in the libpng test program of things I've tried. None of them produces the desired output. What's really frustrating is that Chrome and Preview produce different results. I have no idea which is correct or closest to correct or what "correct" even means.
The more I read about this, the more I think I should just settle for "oh well, it's noticeably wrong but I guess it's good enough *sigh*".
Viewing Experiments
I wrote two identical programs for viewing PNGs. They both produce the desired output (sampling with DCM returns 0 63 127 191 255).
Qt Viewer
#include <iostream>
#include <QtWidgets/qlabel.h>
#include <QtWidgets/qmainwindow.h>
#include <QtWidgets/qapplication.h>
int main(int argc, char **argv) {
if (argc != 2) {
std::cerr << "qt_render <file>\n";
return EXIT_FAILURE;
}
QImage image{argv[1]};
if (image.isNull()) {
std::cerr << "Failed to load image\n";
return EXIT_FAILURE;
}
image = image.scaled(image.size() * 64);
QApplication app{argc, argv};
QMainWindow window;
window.setWindowTitle(argv[1]);
window.setFixedSize(image.size());
QLabel label{&window};
QPixmap pixmap;
if (!pixmap.convertFromImage(image)) {
std::cerr << "Failed to convert surface to texture\n";
return EXIT_FAILURE;
}
label.setPixmap(pixmap);
label.setFixedSize(image.size());
window.show();
return app.exec();
}
SDL2 Libpng Viewer
#include <iostream>
#include <SDL2/SDL.h>
#include <libpng16/png.h>
template <typename... Args>
[[noreturn]] void fatalError(Args &&... args) {
(std::cerr << ... << args) << '\n';
throw std::exception{};
}
void checkErr(const int errorCode) {
if (errorCode != 0) {
fatalError("Error: ", SDL_GetError());
}
}
template <typename T>
T *checkNull(T *ptr) {
if (ptr == nullptr) {
fatalError("Error: ", SDL_GetError());
} else {
return ptr;
}
}
struct FileCloser {
void operator()(std::FILE *file) const noexcept {
std::fclose(file);
}
};
using File = std::unique_ptr<std::FILE, FileCloser>;
File openFile(const char *path, const char *mode) {
std::FILE *file = std::fopen(path, mode);
if (!file) {
fatalError("Failed to open file");
} else {
return File{file};
}
}
struct WindowDestroyer {
void operator()(SDL_Window *window) const noexcept {
SDL_DestroyWindow(window);
}
};
using Window = std::unique_ptr<SDL_Window, WindowDestroyer>;
struct SurfaceDestroyer {
void operator()(SDL_Surface *surface) const noexcept {
SDL_FreeSurface(surface);
}
};
using Surface = std::unique_ptr<SDL_Surface, SurfaceDestroyer>;
struct TextureDestroyer {
void operator()(SDL_Texture *texture) const noexcept {
SDL_DestroyTexture(texture);
}
};
using Texture = std::unique_ptr<SDL_Texture, TextureDestroyer>;
struct RendererDestroyer {
void operator()(SDL_Renderer *renderer) const noexcept {
SDL_DestroyRenderer(renderer);
}
};
using Renderer = std::unique_ptr<SDL_Renderer, RendererDestroyer>;
class SurfaceLock {
public:
explicit SurfaceLock(SDL_Surface *surface)
: surface{surface} {
SDL_LockSurface(surface);
}
~SurfaceLock() {
SDL_UnlockSurface(surface);
}
private:
SDL_Surface *surface;
};
Surface createSurface(png_structp pngPtr, png_infop infoPtr) {
const png_bytepp rows = png_get_rows(pngPtr, infoPtr);
const int width = png_get_image_width(pngPtr, infoPtr);
const int height = png_get_image_height(pngPtr, infoPtr);
Surface surface = Surface{checkNull(SDL_CreateRGBSurfaceWithFormat(
0, width, height, 24, SDL_PIXELFORMAT_RGB24
))};
{
SurfaceLock lock{surface.get()};
for (int y = 0; y != height; ++y) {
uint8_t *dst = static_cast<uint8_t *>(surface->pixels);
dst += y * surface->pitch;
std::memcpy(dst, rows[y], width * 3);
}
}
return surface;
}
void doMain(int argc, char **argv) {
if (argc != 2) {
fatalError("sdl_render <file>");
}
File file = openFile(argv[1], "rb");
png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!pngPtr) {
fatalError("Failed to initialize read struct\n");
}
png_infop infoPtr = png_create_info_struct(pngPtr);
if (!infoPtr) {
png_destroy_read_struct(&pngPtr, nullptr, nullptr);
fatalError("Failed to initialize info struct\n");
}
if (setjmp(png_jmpbuf(pngPtr))) {
png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);
fatalError("Failed to set jmp buf");
}
png_init_io(pngPtr, file.get());
png_read_png(pngPtr, infoPtr, PNG_TRANSFORM_STRIP_ALPHA, nullptr);
Surface surface = createSurface(pngPtr, infoPtr);
png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);
checkErr(SDL_Init(SDL_INIT_VIDEO));
std::atexit(SDL_Quit);
Window window = Window{checkNull(SDL_CreateWindow(
argv[1], SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, surface->w * 64, surface->h * 64, 0
))};
Renderer renderer = Renderer{checkNull(SDL_CreateRenderer(
window.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
))};
Texture texture = Texture{checkNull(SDL_CreateTextureFromSurface(
renderer.get(), surface.get()
))};
surface.reset();
while (true) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
return;
}
}
SDL_RenderCopy(renderer.get(), texture.get(), nullptr, nullptr);
SDL_RenderPresent(renderer.get());
}
}
int main(int argc, char **argv) {
try {
doMain(argc, argv);
} catch (...) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
I'm tempted to write an SDL2, OpenGL, Libpng viewer just to be sure but OpenGL is kind of a hassle. My application is aimed at making sprites and textures for games so if it works with the SDL2 render API and OpenGL then I guess everything is fine. I haven't done any experiments with external monitors yet. Putting sRGB, gAMA and cHRM chunks in the PNG doesn't have any effect on the output of either viewer. I'm not sure if this is good or bad. On the surface, it looks like my problem has just disappeared. I'd still like someone to explain my observations.
ColorSync Utility
I've discovered a new tool and now I think I know what's going on...
This can be accomplished with ImageMagick.
FYI different photo editing programs manage PNG metadata differently, so be aware of this. For example, Mac's Preview app automatically attaches a sRGB IEC61966-2.1 color profile to edited PNG files that do not have an existing color profile. This behavior not only changes the colors, but also impacts the file size.
To make image file comparisons, I use the following ImageMagick command (for each file):
magick identify -verbose insert/image/filepath/here.png
Also, if you want to strip all PNG metadata, use the following ImageMagick command:
convert -strip insert/original/image/filepath/here.png insert/NEW/image/filepath/here2.png
I'm having trouble displaying an image (PNG extracted with libpng) into an XCB window, it is always entirely empty/white. I'm pretty sure the PNG extraction is correct since I can perfectly re-write it into another file.
I've tried everything I found (explanations, guides, documentation) and I'm running out of ideas:
Creating an xcb_pixmap_t calling xcb_create_pixmap_from_bitmap_data() with the data taken from the PNG, then calling xcb_copy_area() into the EXPOSE part of the event loop.
Creating an xcb_image_t* calling xcb_image_create_from_bitmap_data() then trying to map it to the window with xcb_image_put(). I've even tried to display each pixel with xcb_image_put_pixel(), but without success.
Code sample:
xcb_pixmap_t pixmap = xcb_create_pixmap_from_bitmap_data(
connection, // xcb_connect(0, 0) (type: xcb_connection_t*)
window, // xcb_generate_id(connection) (type: xcb_window_t)
img.getData(), // uint8_t*
img.getWidth(), // 128
img.getHeight(), // 128
img.getBitDepth(), // 8
screen->black_pixel, // screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data (type: xcb_screen_t*)
screen->white_pixel,
nullptr);
// "img" is an instance of my own custom class, result of PNG reading
xcb_image_t* image = xcb_image_create_from_bitmap_data(
img.getData(),
img.getWidth(),
img.getHeight()); // image->data seems fine
xcb_image_put(connection,
window,
graphicsContext,
image, 0, 0, 0); // This does nothing
for (unsigned int i = 0; i < screen->height_in_pixels; ++i)
for (unsigned int j = 0; j < screen->width_in_pixels; ++j)
xcb_image_put_pixel(image, j, i, 0); // Displays nothing
[...]
// Into event loop
case XCB_EXPOSE: {
xcb_expose_event_t* exposeEvent = reinterpret_cast<xcb_expose_event_t*>(event);
xcb_copy_area(connection,
pixmap,
window,
graphicsContext,
exposeEvent->x, exposeEvent->y, // Top left x & y coordinates of the source's region to copy
exposeEvent->x, exposeEvent->y, // Top left x & y coordinates of the destination's region to copy to
exposeEvent->width,
exposeEvent->height);
xcb_flush(connection);
break;
}
From the examples I found I saw that it didn't need a colormap, but could that be the case? Could anyone tell me where I've gone wrong?
I threw together a simple xcb image viewer about 4 years ago, but just noticed this question, so apologies for the necromancy.
It uses xcb_image, stb_image and nanosvg, but compiles to a relatively small static binary (with a musl or uclibc toolchain)
#include <xcb/xcb.h>
#include <xcb/xcb_image.h>
#define STBI_NO_HDR
#define STBI_NO_LINEAR
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"
int main(int argc, char **argv){
xcb_connection_t *c = xcb_connect(0, 0);
xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
int w, h, n,
depth = s->root_depth,
win_class = XCB_WINDOW_CLASS_INPUT_OUTPUT,
format = XCB_IMAGE_FORMAT_Z_PIXMAP;
xcb_colormap_t colormap = s->default_colormap;
xcb_drawable_t win = xcb_generate_id(c);
xcb_gcontext_t gc = xcb_generate_id(c);
xcb_pixmap_t pixmap = xcb_generate_id(c);
xcb_generic_event_t *ev;
xcb_image_t *image;
NSVGimage *shapes = NULL;
NSVGrasterizer *rast = NULL;
char *data = NULL;
unsigned *dp;
size_t i, len;
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
value_mask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS,
values[] = { s->black_pixel, value_mask };
if (argc<2) return -1;
if ((data = stbi_load(argv[1], &w, &h, &n, 4)))
;
else if ((shapes = nsvgParseFromFile(argv[1], "px", 96.0f))) {
w = (int)shapes->width;
h = (int)shapes->height;
rast = nsvgCreateRasterizer();
data = malloc(w*h*4);
nsvgRasterize(rast, shapes, 0,0,1, data, w, h, w*4);
}else return -1;
for(i=0,len=w*h,dp=(unsigned *)data;i<len;i++) //rgba to bgra
dp[i]=dp[i]&0xff00ff00|((dp[i]>>16)&0xFF)|((dp[i]<<16)&0xFF0000);
xcb_create_window(c,depth,win,s->root,0,0,w,h,1,win_class,s->root_visual,mask,values);
xcb_create_pixmap(c,depth,pixmap,win,w,h);
xcb_create_gc(c,gc,pixmap,0,NULL);
image = xcb_image_create_native(c,w,h,format,depth,data,w*h*4,data);
xcb_image_put(c, pixmap, gc, image, 0, 0, 0);
xcb_image_destroy(image);
xcb_map_window(c, win);
xcb_flush(c);
while ((ev = xcb_wait_for_event(c))) {
switch (ev->response_type & ~0x80){
case XCB_EXPOSE: {
xcb_expose_event_t *x = (xcb_expose_event_t *)ev;
xcb_copy_area(c,pixmap,win,gc,x->x,x->y,x->x,x->y,x->width,x->height);
xcb_flush(c);
}break;
case XCB_BUTTON_PRESS: goto end;
default: break;
}
}
end:
xcb_free_pixmap(c, pixmap);
xcb_disconnect(c);
return 0;
}
I want to play video file, that i obtained from IP-camera (H264-codec) using libVLC and OpenCV, so i took the code from this post, then created project in VS 2010, and put my mp4 file into project folder ("5.mp4"). When i started it - i got this errors:
main error: open of `5.mp4' failed
main error: Your input can't be opened
main error: VLC is unable to open the MRL '5.mp4'. Check the log for details.
Here's my code:
#include <vlc/vlc.h>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <stdio.h>
using namespace cv;
using namespace std;
struct VideoDataStruct {
int param;
};
int done = 0;
libvlc_media_player_t *mp;
unsigned int videoBufferSize = 0;
uint8_t *videoBuffer = 0;
void cbVideoPrerender(void *p_video_data, uint8_t **pp_pixel_buffer, int size) {
// Locking
if (size > videoBufferSize || !videoBuffer)
{
printf("Reallocate raw video buffer\n");
free(videoBuffer);
videoBuffer = (uint8_t *) malloc(size);
videoBufferSize = size;
}
*pp_pixel_buffer = videoBuffer;
}
void cbVideoPostrender(void *p_video_data, uint8_t *p_pixel_buffer, int width, int height, int pixel_pitch, int size, int64_t pts) {
// Unlocking
//CloseHandle(hMutex);
}
static void handleEvent(const libvlc_event_t* pEvt, void* pUserData) {
libvlc_time_t time;
switch(pEvt->type)
{
case libvlc_MediaPlayerTimeChanged:
time = libvlc_media_player_get_time(mp);
printf("MediaPlayerTimeChanged %lld ms\n", (long long)time);
break;
case libvlc_MediaPlayerEndReached:
printf ("MediaPlayerEndReached\n");
done = 1;
break;
default:
printf("%s\n", libvlc_event_type_name(pEvt->type));
}
}
int main(int argc, char* argv[]) {
// VLC pointers
libvlc_instance_t *inst;
libvlc_media_t *m;
void *pUserData = 0;
VideoDataStruct dataStruct;
// VLC options
char smem_options[1000];
// RV24
sprintf(smem_options
, "#transcode{vcodec=RV24}:smem{"
"video-prerender-callback=%lld,"
"video-postrender-callback=%lld,"
"video-data=%lld,"
"no-time-sync},"
, (long long int)(intptr_t)(void*)&cbVideoPrerender
, (long long int)(intptr_t)(void*)&cbVideoPostrender
, (long long int)(intptr_t)(void*)&dataStruct
);
const char * const vlc_args[] = {
"-I", "dummy", // Don't use any interface
"--ignore-config", // Don't use VLC's config
"--extraintf=logger", // Log anything
"--verbose=1", // Be verbose
"--sout", smem_options // Stream to memory
};
// We launch VLC
inst = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
/* Create a new item */
m = libvlc_media_new_location(inst, "5.mp4");
/* Create a media player playing environement */
mp = libvlc_media_player_new_from_media (m);
libvlc_event_manager_t* eventManager = libvlc_media_player_event_manager(mp);
libvlc_event_attach(eventManager, libvlc_MediaPlayerTimeChanged, handleEvent, pUserData);
libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, handleEvent, pUserData);
libvlc_event_attach(eventManager, libvlc_MediaPlayerPositionChanged, handleEvent, pUserData);
libvlc_video_set_format(mp, "RV24", 1280, 720, 1280* 3 );
/* play the media_player */
libvlc_media_player_play (mp);
while(1)
{
if(videoBuffer) // Check for invalid input
{
// CV_8UC3 = 8 bits, 3 chanels
Mat img = Mat(Size(1280, 720), CV_8UC3, videoBuffer);
// cvtColor(img, img, CV_RGB2BGR);
namedWindow("Display window", WINDOW_AUTOSIZE); // Create a window for display.
imshow("Display window", img); // Show our image inside it.
}
}
libvlc_release (inst);
}
I guess, that is easy to fix, but i could't find any information at the Internet. I also tryied to put it into "C:\5.mp4", but i got the same errors. Thanks for any help.
EDIT:
Ok, so i fixed this issue, i need to put file:/// before "5.mp4", now my video is playing, but it looks like this:
EDIT02
Ok, with "*.avi" everything looks good, so i guess problem with this file - i recorded it frop IP-camera, using VLC, and saved it into *.mp4
Ok, so i found the problem, i made a mistake with video resolution, original resolution is 2560x1536, so when i put libvlc_video_set_format(mp,2560,1536,2560 *3); my picture looks fine, so after i pass it to OpenCV i could resize it.
I'm struggling with converting a QVideoFrame (QT) into a AVFrame in order to encode video coming from a webcam.
Documentation for QVideoFrame: http://qt-project.org/doc/qt-5/qvideoframe.html
I understand the basics of image formats, stride and such but I'm missing something. This is what I've got so far, adapted from a libav example (https://libav.org/doxygen/release/0.8/libavformat_2output-example_8c-example.html):
static void fill_yuv_image(const QVideoFrame &frame, AVFrame *pict, int frame_index, int width, int height)
{
pict->pts = frame.startTime() * 1000000.0; // time_base is 1/1000000
pict->width = frame.width();
pict->height = frame.height();
pict->format = STREAM_PIX_FMT; //todo: get this from the frame
pict->data[0] = (uint8_t*)frame.bits();
pict->linesize[0] = frame.bytesPerLine();
}
After which I'm attempting to encode:
AVPacket pkt;
int got_packet_ptr = 0;
int success = avcodec_encode_video2(c, &pkt, picture, &got_packet_ptr);
/* if zero size, it means the image was buffered */
if (success == 0) {
/* write the compressed frame in the media file */
ret = av_interleaved_write_frame(oc, &pkt);
} else {
ret = 0;
}
It's returning an error about the stride not matching. Any help would be greatly appreciated. Thanks!
I am trying to get a knight on a horse (inauspiciously named "guy") to run across the screen. The knight currently exists in my directory as 2 .png files, to simulate some poorly animated galloping. I was able to get him to appear when he was a .bmp, but I would like to utilize the transparency of png files - I've also tried and failed with opening tif files. How can I alter my code in order to get him to appear from a .png loaded into SDL correctly?
Here is my .cpp file:
#include "SDL/SDL.h"
#include <iostream>
#include "source_sdl.h"
# include <string>
using namespace std;
int source_sdl( int argc, char* args[] ) {
int switch = 1;
int running = 1;
// surface & rect declarations
SDL_Surface* ground = NULL;
SDL_Surface* guy = NULL;
SDL_Surface* guy2 = NULL;
SDL_Rect guylocationRect;
SDL_Rect groundlocationRect;
// initialize SDL & the screen
SDL_Init( SDL_INIT_EVERYTHING );
screen = SDL_SetVideoMode( 875, 625, 32, SDL_SWSURFACE );
// open .png files
SDL_RWops* guy_rwop;
SDL_RWops* guy2_rwop;
guy_rwop = SDL_RWFromFile("tiffKnight.png", "rb");
guy2_rwop = SDL_RWFromFile("tiffKnight2.png", "rb");
guy = IMG_LoadPNG_RW(guy_rwop);
guy2 = IMG_LoadPNG_RW(guy2_rwop);
guylocationRect.x = 300;
guylocationRect.y = 300;
groundlocationRect.x = 300;
groundlocationRect.y = 300;
SDL_Event occur;
// animation loop (currently endless)
while (running == 1){
SDL_Flip( screen );
SDL_Delay( 300 );
if (gallop > 89) gallop=0;
// draw the ground
for( int yu = 0; yu<35; yu++){
groundlocationRect.x=25*yu;
groundlocationRect.y=5*25;
SDL_BlitSurface( ground, NULL, screen, &groundlocationRect );
}
// draw the gallopping
guylocationRect.x=10*gallop;
guylocationRect.y=5*25;
if( switch ){
SDL_BlitSurface( guy, NULL, screen, &guylocationRect );
}else{
SDL_BlitSurface( guy2, NULL, screen, &guylocationRect );
}
gallop++;
switch = (switch+1)%2;
for(int u = 6; u < 25; u++){
for(int yu = 0; yu < 35; yu++){
groundlocationRect.x = 25*yu;
groundlocationRect.y = 25*u;
SDL_BlitSurface( ground, NULL, screen, &groundlocationRect );
}
}
}
SDL_FreeSurface( guy );
SDL_FreeSurface( guy2 );
SDL_FreeSurface( ground );
}
As I currently have it, the knight does not appear and I receive no errors (a consequence of the SDL screen being open?) Fail checks such as
if(!guy) {
cout << "IMG_LoadPNG_RW: %s\n" << IMG_GetError();
}
Have also yielded no results. my .h file is simply:
#include "SDL/SDL.h"
#include <iostream>
using namespace std;
int source_sdl( int argc, char* args[] );
And my main.cpp:
#include "SDL/SDL.h"
#include <iostream>
#include "source_sdl.h"
using namespace std;
int main( int argc, char* args[] ){
source_sdl( argc, args );
}
If you really want to stick with SDL in C++, I suggest you to use the SDL_image library and use a function like :
SDL_Surface * load_image(std::string const & filename)
{
SDL_Surface * img = NULL;
SDL_Surface * tmp = IMG_Load(filename.c_str());
if (tmp)
{
img = SDL_DisplayFormatAlpha(tmp);
SDL_FreeSurface(tmp);
}
return img;
}
An example of a more modern and safe approach would looke like this:
using surface_ptr = std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)>;
surface_ptr load_image (std::string const & filename)
{
surface_ptr img { nullptr, &SDL_FreeSurface };
surface_ptr tmp { IMG_Load(filename.c_str()), &SDL_FreeSurface };
if (tmp)
img.reset(SDL_DisplayFormatAlpha(tmp.get()));
return img;
}
Or better, use an existing C++ Binding like libSDL2pp (I have nothing to do with them).