How to execute a ffmpeg code on a GPU without using the command line? - c

We have written a short code in C code to read a video file, using common libraries as libavcodec, libavformat, etc.
The code is running smoothly but only using the CPU resources. We'd need to run the code on the GPU (Nvidia GeForce 940MX and 1080Ti). Is there a way to force the code to be run on the GPU?
While using the command line (e.g., ffmpeg -hwaccel cuvid -i vid.mp4 out.avi) things are fine, we are not able to have it working on the GPU from the source code.
We are working with Ubuntu 18.04, and ffmpeg correctly compiled with CUDA 9.2

There are pretty good examples for using libav (ffmpeg) for encoding and decoding video at https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples.
For what you need is demuxing_decoding.c example and change the lines 166 which is:
/* find decoder for the stream */
dec = avcodec_find_decoder(st->codecpar->codec_id);
with
/* find decoder for the stream */
if (st->codecpar->codec_id == AV_CODEC_ID_H264)
{
dec = avcodec_find_decoder_by_name("h264_cuvid");
}
else if (st->codecpar->codec_id == AV_CODEC_ID_HEVC)
{
dec = avcodec_find_decoder_by_name("hevc_cuvid");
}
else
{
dec = avcodec_find_decoder(st->codecpar->codec_id);
}
add/change lines for other formats. And make sure your FFmpeg compiled with --enable-cuda --enable-cuvid
In my tests I got error comes from line 85: because nvdec (hevc_cuvid) uses p010 internal format for 10bit (input is yuv420p10). Which means decoded frame will be either NV12 pixel format or P010 depending on bit depth. I hope you are familiar with pixel formats.
Hope that helps.

Related

Changing playback speed using gstreamer

I am currently working on the gstreamer tutorials, in particular the one about playback speed adjustments. I pasted the example code into a file which I compiled with the flags pkg-config --cflags --libs gstreamer-1.0 (my gstreamer version is 1.20.5)
I tried to change the playback rates using the keys S / s, got the corresponding prints (Current rate: 0.5 etc.) but the playback speed stayed constant at 1. I thought that the failure to change the playback speed was due to the source being a remote file, so I changed the code to use local files (as command line arguments) instead:
gchar buffer[4096];
g_snprintf(buffer, 4096, "playbin uri=file://%s", argv[1]);
/* Build the pipeline */
data.pipeline = gst_parse_launch(buffer, &error);
I also switched from the video sink to an audio sink (audio is sufficient for my cases).
I then noticed that whether or not the rate changed works is (apparently) up to the type of the file I am opening: When I open a local ogg file, the playback speed changes, when I open an mp3 instead, nothing happens.
Is this a bug in gstreamer, or do I need a more sophisticated pipeline in order to get the approach to work with different media types (local files would be sufficient for my needs)?
Edit: Complete code, sample mp3

Using parallel decoder in libavcodec/ffmpeg

The problem
I am writing a simple program in C language which makes use of libavcodec (https://github.com/Dr-Noob/framepos/blob/master/framepos.c)
I have been working with h264 videos. While the decoding works, I can see that it's very slow, since it only uses 1 CPU core (I checked it with top). On the other hand, I know that ffmpeg, which uses the same libavocdec installed in my system, makes use of the parallel h264 decoder. I can test it with:
ffmpeg -c:v h264 -i test.mkv -f null -
With top I can see that it's running in parallel, and the speed is noticeably faster. I would like a solution that always gives me the possibility of decoding the video using all the CPU cores, not only in the case of the h264 codec.
My research so far
Looking at the ffmpeg code, one can see that, to obtain the AVCodec, it uses the function find_codec_or_die. This will end up using avcodec_find_decoder_by_name. Actually, if in my program I use this function, asking for the h264 decoder, I still get the sequential version. Moreover, using gdb in ffmpeg I have seen that the AVCodec in ffmpeg is called ff_h264_decoder, while in my code, gdb does not know which specific type is the codec. The ff suffix makes me think that this one is the parallel decoder (because it looks like ff has something to do with parallel in the ffmpeg context (https://ffmpeg.org/doxygen/2.7/pthread__frame_8c.html)). However, it seems that I am unable to get this codec.
What can I do to decode video in parallel using libavcodec in C?
Posting gkv311 comment as an answer for future reference.
AVCodec does not have multi-threading functionality. It is stored inside AVCodecContex. So, a posible scheme to run the codec in parallel:
AVCodec *codec = avcodec_find_decoder
AVCodecContext *ctx = avcodec_alloc_context3
ctx->thread_count = n_threads;
ctx->thread_type = FF_THREAD_FRAME;
avcodec_open2(ctx, fmt_ctx->video_codec, NULL)

How to play .m4s file given in mpd of MPEG-DASH on player?

I have downloaded the MPDs "http://dash.edgesuite.net/adobe/hdworld_dash/HDWorld.mpd" and all related .m4s files.
I tried running it on VLC player. But the format is not recognized by VLC player.
I have downloaded this media segment using wget (1 to 14 segments are available)
http://dash.edgesuite.net/adobe/hdworld_dash/hdworld_seg_hdworld_0696kbps_ffmpeg.mp4.video_temp2.m4s.
Can anybody tell me solution how to run .m4s format file on player?
System: Ubuntu 11.10
You need the initialization segment. It is often named "00" or "init" or doesn't have a sequence number like the other files, and often ends in ".mp4" rather than ".m4s". Then you just concatenate the files together. You can start anywhere in the sequence so long as you begin with the initialization segment.
For example
cat init.mp4 *.m4s > output.mp4
Then you have a playable mp4 file with content, assuming there is no encryption (DRM) applied to it.
.m4s file format is ISO Base Media File. i.e. MPEG-4 Part 14. read specs for more info you may get m4s player for windows. As far as I know on Linux platform GPAC will help. You can create your own MPD from any media source using MP4Box a GPAC tool.
You can use MP4Client for playing your DASHed Media from MPD. Actually .m4s's separate segment is not able to play by its own bcoz player should know Codec and mime type to play any media and m4s is not supported by any player, i.e. it has its own header and data (moof & mdat).
For playing MPD which contains many m4s segment (you can make your own MPD or download each audio and video segment separately from any MPD & put it in to a same folder):
install GPAC.
$MP4Client MYWorld.mpd will open Osmo4 player and you can see your video is playing. Enjoy..
FYI, local streaming server can also play this video:
$MP4Client http://localhost/MYWorld.mpd
if not working change segmentAlignment flag, i.e. <AdaptationSet segmentAlignment="true" subsegmentAlignment="true">.
you can play it using GPAC player, installing it with all the third party codecs also -
http://gpac.wp.mines-telecom.fr/player/
some ppl claim that they are able use vlc, i have not tested it.
Try this in the OSX terminal:
open -a Osmo4 example.mpd
It works for me.

Reading output of a USB webcam in Linux

I was experimenting with a little bit with fread and fwrite in C. So i wrote this little program in C to get data from a webcam and dump it into a file. The following is the source:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 307200 // number of pixels (640x480 for my webcam)
int main() {
FILE *camera, *grab;
camera=fopen("/dev/video0", "rb");
grab=fopen("grab.raw", "wb");
float data[SIZE];
fread(data, sizeof(data[0]), SIZE, camera);
fwrite(data, sizeof(data[0]), SIZE, grab);
fclose(camera);
fclose(grab);
return 0;
}
The program works when compiled (gcc -o snap camera.c). What took me by surprise was that the output file was not a raw data dump but a JPEG file. Output of the file command on linux on the programs output file showed it was a JPEG image data: JFIF Standard 1.01. The file was viewable on an image viewer, although a little saturated.
How or why does this happen? I did not use any JPEG encoding libraries in the source or the program. Does the camera output JPEG natively? The webcam is a Sony Playstation 2 EyeToy which was manufactured by Logitech. The system is Debian Linux.
The Sony EyeToy has an OV7648 sensor with the quite popular OV519 bridge. The OV519 outputs frames in JPEG format - and if I remember correctly from my own cameras that's the only format that it supports.
Cameras like this require either application support, or a special driver that will decompress the frames before delivery to userspace. Apparently in your case the driver delivers the JPEG frames in their original form, which is why you are getting JPEG data in the output.
BTW, you should really have a look at the Video4Linux2 API for the proper way to access video devices on Linux - a simple open()/read()/close() is generally not enough...

dm365 mpeg4 encoder P-Frames

I am implementing the operation of encoding video with TI DM365 mpeg4 encoder and containerizing it with ffmpeg mp4 container using a dummy FMP4 codec to produce headers and footers. While the container is proven to be working correctly using similar Intel based mpeg4 encoder, the dm365 gives a mosaic result if P frames are used at all. Using only I frames works, but I would like to minimize amount of data stored.
The example of the result can be viewed here. Settings are 1-Iframe, 9-Pframes
TI developers didn't answer my question regarding this in 2 days, so I am trying to get help here.
This may help, a TI data sheet on the various settings/parameters and their effect. Apologies if it is telling you stuff you already know...
TI Data Sheet spraba9.pdf

Resources