
Recherche avancée
Médias (10)
-
Demon Seed
26 septembre 2011, par
Mis à jour : Septembre 2011
Langue : English
Type : Audio
-
Demon seed (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
The four of us are dying (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Corona radiata (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Lights in the sky (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Head down (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
Autres articles (40)
-
Personnaliser en ajoutant son logo, sa bannière ou son image de fond
5 septembre 2013, parCertains thèmes prennent en compte trois éléments de personnalisation : l’ajout d’un logo ; l’ajout d’une bannière l’ajout d’une image de fond ;
-
La file d’attente de SPIPmotion
28 novembre 2010, parUne file d’attente stockée dans la base de donnée
Lors de son installation, SPIPmotion crée une nouvelle table dans la base de donnée intitulée spip_spipmotion_attentes.
Cette nouvelle table est constituée des champs suivants : id_spipmotion_attente, l’identifiant numérique unique de la tâche à traiter ; id_document, l’identifiant numérique du document original à encoder ; id_objet l’identifiant unique de l’objet auquel le document encodé devra être attaché automatiquement ; objet, le type d’objet auquel (...) -
Ecrire une actualité
21 juin 2013, parPrésentez les changements dans votre MédiaSPIP ou les actualités de vos projets sur votre MédiaSPIP grâce à la rubrique actualités.
Dans le thème par défaut spipeo de MédiaSPIP, les actualités sont affichées en bas de la page principale sous les éditoriaux.
Vous pouvez personnaliser le formulaire de création d’une actualité.
Formulaire de création d’une actualité Dans le cas d’un document de type actualité, les champs proposés par défaut sont : Date de publication ( personnaliser la date de publication ) (...)
Sur d’autres sites (4543)
-
How to convert ffmpeg video frame to YUV444 ?
21 octobre 2019, par Edward SeverinsenI have been following a tutorial on how to use ffmpeg and SDL to make a simple video player with no audio (yet). While looking through the tutorial I realized it was out of date and many of the functions it used, for both ffmpeg and SDL, were deprecated. So I searched for an up-to-date solution and found a stackoverflow question answer that completed what the tutorial was missing.
However, it uses YUV420 which is of low quality. I want to implement YUV444 and after studying chroma-subsampling for a bit and looking at the different formats for YUV am confused as to how to implement it. From what I understand YUV420 is a quarter of the quality YUV444 is. YUV444 means every pixel has its own chroma sample and as such is more detailed while YUV420 means pixels are grouped together and have the same chroma sample and therefore is less detailed.
And from what I understand the different formats of YUV(420, 422, 444) are different in the way they order y, u, and v. All of this is a bit overwhelming because I haven’t done much with codecs, conversions, etc. Any help would be much appreciated and if additional info is needed please let me know before downvoting.
Here is the code from the answer I mentioned concerning the conversion to YUV420 :
texture = SDL_CreateTexture(
renderer,
SDL_PIXELFORMAT_YV12,
SDL_TEXTUREACCESS_STREAMING,
pCodecCtx->width,
pCodecCtx->height
);
if (!texture) {
fprintf(stderr, "SDL: could not create texture - exiting\n");
exit(1);
}
// initialize SWS context for software scaling
sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_YUV420P,
SWS_BILINEAR,
NULL,
NULL,
NULL);
// set up YV12 pixel array (12 bits per pixel)
yPlaneSz = pCodecCtx->width * pCodecCtx->height;
uvPlaneSz = pCodecCtx->width * pCodecCtx->height / 4;
yPlane = (Uint8*)malloc(yPlaneSz);
uPlane = (Uint8*)malloc(uvPlaneSz);
vPlane = (Uint8*)malloc(uvPlaneSz);
if (!yPlane || !uPlane || !vPlane) {
fprintf(stderr, "Could not allocate pixel buffers - exiting\n");
exit(1);
}
uvPitch = pCodecCtx->width / 2;
while (av_read_frame(pFormatCtx, &packet) >= 0) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStream) {
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Did we get a video frame?
if (frameFinished) {
AVPicture pict;
pict.data[0] = yPlane;
pict.data[1] = uPlane;
pict.data[2] = vPlane;
pict.linesize[0] = pCodecCtx->width;
pict.linesize[1] = uvPitch;
pict.linesize[2] = uvPitch;
// Convert the image into YUV format that SDL uses
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pict.data,
pict.linesize);
SDL_UpdateYUVTexture(
texture,
NULL,
yPlane,
pCodecCtx->width,
uPlane,
uvPitch,
vPlane,
uvPitch
);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
SDL_PollEvent(&event);
switch (event.type) {
case SDL_QUIT:
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(screen);
SDL_Quit();
exit(0);
break;
default:
break;
}
}
// Free the YUV frame
av_frame_free(&pFrame);
free(yPlane);
free(uPlane);
free(vPlane);
// Close the codec
avcodec_close(pCodecCtx);
avcodec_close(pCodecCtxOrig);
// Close the video file
avformat_close_input(&pFormatCtx);EDIT :
After more research I learned that in YUV420 is stored with all Y’s first then a combination of U and V bytes one after another as illustrated by this image :
(source : wikimedia.org)However I also learned that YUV444 is stored in the order U, Y, V and repeats like this picture shows :
I tried changing some things around in code :
// I changed SDL_PIXELFORMAT_YV12 to SDL_PIXELFORMAT_UYVY
// as to reflect the order of YUV444
texture = SDL_CreateTexture(
renderer,
SDL_PIXELFORMAT_UYVY,
SDL_TEXTUREACCESS_STREAMING,
pCodecCtx->width,
pCodecCtx->height
);
if (!texture) {
fprintf(stderr, "SDL: could not create texture - exiting\n");
exit(1);
}
// Changed AV_PIX_FMT_YUV420P to AV_PIX_FMT_YUV444P
// for rather obvious reasons
sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_YUV444P,
SWS_BILINEAR,
NULL,
NULL,
NULL);
// There are as many Y, U and V bytes as pixels I just
// made yPlaneSz and uvPlaneSz equal to the number of pixels
yPlaneSz = pCodecCtx->width * pCodecCtx->height;
uvPlaneSz = pCodecCtx->width * pCodecCtx->height;
yPlane = (Uint8*)malloc(yPlaneSz);
uPlane = (Uint8*)malloc(uvPlaneSz);
vPlane = (Uint8*)malloc(uvPlaneSz);
if (!yPlane || !uPlane || !vPlane) {
fprintf(stderr, "Could not allocate pixel buffers - exiting\n");
exit(1);
}
uvPitch = pCodecCtx->width * 2;
while (av_read_frame(pFormatCtx, &packet) >= 0) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStream) {
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Rearranged the order of the planes to reflect UYV order
// then set linesize to the number of Y, U and V bytes
// per row
if (frameFinished) {
AVPicture pict;
pict.data[0] = uPlane;
pict.data[1] = yPlane;
pict.data[2] = vPlane;
pict.linesize[0] = pCodecCtx->width;
pict.linesize[1] = pCodecCtx->width;
pict.linesize[2] = pCodecCtx->width;
// Convert the image into YUV format that SDL uses
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pict.data,
pict.linesize);
SDL_UpdateYUVTexture(
texture,
NULL,
yPlane,
1,
uPlane,
uvPitch,
vPlane,
uvPitch
);
//.................................................But now I get an access violation at the call to
SDL_UpdateYUVTexture
... I’m honestly not sure what’s wrong. I think it may have to do with settingAVPicture pic
’s memberdata
andlinesize
improperly but I’m not positive. -
How to measure the performance of a newsletter (or any email) with Matomo
19 décembre 2017, par InnoCraftTo be able to grow your business, it is crucial to track all your marketing efforts. This includes all newsletters and emails that you share with people outside of your business. Otherwise, you won’t be able to know which of your daily efforts are yielding results.
Are you wondering if it is possible to track the performance of an emailing campaign in Matomo (Piwik) efficiently ? Would you like to know if it is technically easy ? No worries, here is a “How to” tutorial showing you how easily you can track an emailing in Matomo properly.
Different tracking levels for different needs
There are many things that you may be interested to track, for example :
- How many users opened your email
- How many users interacted with the links in your email
- How many users interacted on your website through your email
Let’s have a look at each of these levels.
Step 1 – Tracking email and newsletter openings in Matomo
Tracking email openings requires to add an HTML code to your newsletter. It works through what we call a tracking pixel, a tiny image of 1×1 that is transparent so the user will not be able to see it.
In order to install it, here is an example of what this code looks like :<img src="https://piwik.example.com/piwik.php?idsite=YOUR_PIWIK_WEBSITE_ID&rec=1&bots=1&url=https%3A%2F%2Fexample.com%2Femail-opened%2Fnewsletter_XYZ&action_name=Email%20opened&_rcn=internal%20email%20name&_rck=newsletter_XYZ" style="border:0;” alt="" />
The Matomo tracking pixel explained
The above URL is composed of the following URL parameters which are part of our Tracking API :
- idsite : Corresponds to the ID of the website you would like to track.
- rec : You need to have rec=1 in order for the request to be actually recorded.
- bots : Set it to 1 to include all the connections made to this request, bots included.
- url : corresponds to the URL you would like to display in Matomo (Piwik) every time the email is opened.
- action_name : This is the page name you would like to be tracked when the email is opened.
- _rcn : The name you would like to give to your campaign.
- _rck : The keyword you may like to use in order to summarize the content of your newsletter.
You may have noticed some special characters here such as “%20”, “%2F”. That’s because the URL is encoded. We strongly recommend you to do so in order for your tracking not to break. Many tools are available on the web in order to encode your URLs such as https://www.urlencoder.org/.
If you would like to access the previous tracking code easily, keep in mind that you can always find the tracking code generator within the “Matomo admin panel → Tracking code” :
You can find more information about it on our guide at : How do I track how many users open and read my newsletter emails (using a pixel / beacon) ?
As a result, the information will be pushed as following for any user who opens your email :
To not bias your regular page views on your website with newsletter openings, we recommend tracking newsletter openings into a new website.
Tracking even more data : the user ID example
You can go deeper in your URL tracking by inserting other parameters such as the user id if you have this information within your emailing database. One of the main benefit of tracking the User ID is to connect data across multiple devices and browsers for a given user.
You only need to add the following parameter &uid=XXX where XXX equals the dynamic value of the user ID :
Make sure that UID from your emailing provider is the same as the one used on your website in order for your data to be consistent.
Important note : some email providers are loading email messages by default which results in an opening even if the user did not actually open the email.
Step 2 – Measure the clicks within your emailing
Tracking clicks within an email lets you know with which content readers interacted the most. We recommend tracking all links in all your emails as a campaign, whether it is a newsletter, a custom support email, an email invoice, etc. You might be surprised to see which of your emails lead to conversions and if they don’t, try to tweak those emails, so they might in the future.
Tracking clicks This works thanks to URL campaign tracking. In order to perform this action, you will need to add Matomo (Piwik) URL parameters to all your existing link URLs :
- Website URL : for example “www.your-website.com”.
- Campaign name : for example “pk_campaign=emailing”. Represents the name you would like to give to your campaign.
- Campaign keyword : for example “pk_keyword=name-of-your-article”. Represents the name you would like to give to your content.
- Campaign source : for example “pk_source=newsletter”. Represents the name of the referrer.
- Campaign medium : for example “pk_medium=email”. Represents the type of referrer you are using.
- Campaign content : for example “pk_content=title”. Represents the type of content.
You can find more information about campaign url tracking in our “Tracking marketing campaigns with Matomo” guide.
Here is a sample showing you how you can differentiate some links in a newsletter, all pointing to the same URL :
Once you have added these URL parameters to each of your link, Matomo (Piwik) will clearly indicate the referrer of this specific campaign when a user clicks on a link in the newsletter and visits your website.
Important note : if you do not track your campaigns, it will result in a bad interpretation of your data within Matomo (Piwik) as you will get webmail services or direct entries as referrer instead of your newsletter campaign.
Step 3 – Measure emailing performances on your website
Thanks to Matomo (Piwik) URL campaign parameters, you can now clearly identify the traffic brought through your emailing. You can now specifically isolate users who come from emails by creating a segment :
Once done, you can either have a look at each user specifically through the visitor log report or analyze it as a whole within the rest of the reports.
You can even measure your return on investment directly if goals have been defined. In order to know more about how to track goals within Matomo (Piwik).
Did you like this article ?
If you enjoyed reading this article, do not hesitate to share it around you. Moreover, if there are any topics you would like to write us about in particular, just drop us an email and we will be more than happy to write about it.
The post How to measure the performance of a newsletter (or any email) with Matomo appeared first on Analytics Platform - Matomo.
-
AVIOContext custom stream playback glitches/corruption on UDP stream
21 décembre 2017, par WLGfxI’ve written a general all round player (for Android OS) which plays file based streams as well as streams from network sources, and it all works good. File based streams I’ve got the seeking which works too.
What it is I’m now struggling with is now I’m using
AVIOContext
to latch onto a UDP stream which saves the packet data partially in memory and then to transient storage. This is so I can pause live TV and also seek within it.However, after much faffing about, during playback (seeking is only partial at the moment), either the video frame rate will drop from 25FPS (will be deinterlaced on higher spec devices) down to between 17 and 19 frames per second, or, it will glitch and grey out.
When I playback the record TS data from the file, it plays perfect, so the UDP buffering and writing out the overflow is sound. (This is currently not true now, only currently a minor issue)
I’m at the point were I’ve spent a lot of time on this and I’m at a loss as to why I get either frame drops or glitches.
The class def :
#define PKT_SIZE (188)
#define PKT_SIZE7 (PKT_SIZE * 7)
#define UDP_QUEUE_SIZE (12000)
#define UDP_THRESHOLD (100)
#define FILE_QUEUE_PKTS (200000)
#define AVIO_QUEUE_SIZE (24)
#define AVIO_THRESHOLD (10)
extern "C" {
#include "libavformat/avio.h"
};
/*
* PracticalSocket class as found here with examples:
* http://cs.baylor.edu/~donahoo/practical/CSockets/practical/
*/
#include "PracticalSocket.h"
class FFIOBufferManager2 {
public:
AVIOContext *avioContext = nullptr;
bool quit = false;
char udp_buffer[UDP_QUEUE_SIZE][PKT_SIZE7];
int udp_write_pos, udp_size; // by PKT_SIZE7
char *get_udp_buffer(int index);
int get_udp_buffer_size() { return udp_size; }
int file_write_pos, file_size; // by PKT_SIZE7
std::fstream file_out, file_in;
std::mutex udp_mutex, file_mutex;
std::thread udp_thread, file_thread;
static void udp_thread_func(FFIOBufferManager2 *io, const char *ip, int port);
static void file_thread_func(FFIOBufferManager2 *io, const char *dir);
void udp_thread_run(const char *ip, int port);
void file_thread_run();
char avio_buffer[AVIO_QUEUE_SIZE * 7 * PKT_SIZE];
int64_t avio_read_offset; // controlled by udp mutex (quickest)
static int avio_read(void *ptr, uint8_t *buff, int buf_size);
static int64_t avio_seek(void *ptr, int64_t pos, int whence);
int avio_read_run(uint8_t *buf, int buf_size);
int64_t avio_seek_run(int64_t pos, int whence);
void write_udp_overflow();
void start(const char *ip, int port, const char *dir);
void get_size_and_pos(int64_t *size, int64_t *pos);
~FFIOBufferManager2();
};The classes methods :
#include
#include "FFIOBufferManager2.h"
#include "LOG.h"
void FFIOBufferManager2::start(const char *ip, int port, const char *dir) {
file_write_pos = 0;
file_size = 0;
udp_write_pos = 0;
udp_size = 0;
avio_read_offset = 0;
file_thread = std::thread(&FFIOBufferManager2::file_thread_func, this, dir);
udp_thread = std::thread(&FFIOBufferManager2::udp_thread_func, this, ip, port);
LOGD("Initialising avioContext");
avioContext = avio_alloc_context((uint8_t*)avio_buffer,
AVIO_QUEUE_SIZE * PKT_SIZE7,
0,
this,
avio_read,
NULL,
avio_seek);
}
void FFIOBufferManager2::udp_thread_func(FFIOBufferManager2 *io, const char *ip, int port) {
LOGD("AVIO UDP thread started address %s port %d - %08X", ip, port, (uint)io);
io->udp_thread_run(ip, port); // run inside class
LOGD("AVIO UDP thread stopped");
}
void FFIOBufferManager2::udp_thread_run(const char *ip, int port) {
std::string addr = ip;
UDPSocket socket(addr, (uint16_t)port);
socket.joinGroup(addr);
LOGD("UDP loop starting");
while (!quit) {
if (socket.recv(get_udp_buffer(udp_write_pos), PKT_SIZE7) == PKT_SIZE7) {
udp_mutex.lock();
udp_write_pos = (udp_write_pos + 1) % UDP_QUEUE_SIZE;
udp_size++;
if (udp_size >= UDP_QUEUE_SIZE) udp_size--;
else avio_read_offset += PKT_SIZE7;
udp_mutex.unlock();
}
}
}
void FFIOBufferManager2::file_thread_func(FFIOBufferManager2 *io, const char *dir) {
LOGD("AVIO FILE thread started");
std::string file = dir;
const char *tsfile_name = "/tsdata.ts";
file += tsfile_name;
LOGD("Deleting old file %s", file.c_str());
remove(file.c_str());
{
fstream temp; // create the ts file
temp.open(file.c_str());
temp.close();
}
LOGD("Opening %s for read and write", file.c_str());
io->file_out.open(file, fstream::out | fstream::binary);
io->file_in.open(file, fstream::in | fstream::binary);
io->file_thread_run(); // continue inside the class to lessen pointer use
LOGD("AVIO FILE thread stopped");
}
void FFIOBufferManager2::file_thread_run() {
LOGD("FILE thread run");
if (!file_out.is_open() || !file_in.is_open()) {
LOGE("TS data file, error opening...");
quit = true;
return;
}
int udp_threshold = UDP_QUEUE_SIZE - (UDP_THRESHOLD * 4);
while (!quit) {
if (udp_size >= udp_threshold) write_udp_overflow();
else usleep(1000 * 1);
}
}
void FFIOBufferManager2::write_udp_overflow() {
file_mutex.lock();
udp_mutex.lock();
int udp_write_pos_current = udp_write_pos;
int udp_size_current = udp_size;
udp_mutex.unlock();
int udp_index = udp_write_pos_current - udp_size_current;
if (udp_index < 0) udp_index += UDP_QUEUE_SIZE;
int written = 0;
//file_out.seekp((int64_t)file_write_pos * PKT_SIZE7);
while (written < UDP_THRESHOLD) {
file_out.write(get_udp_buffer(udp_index), PKT_SIZE7);
written++;
udp_index = (udp_index + 1) % UDP_QUEUE_SIZE;
file_write_pos++;
if (file_write_pos >= FILE_QUEUE_PKTS) {
file_write_pos = 0;
file_out.seekp(0);
}
file_size++;
if (file_size > FILE_QUEUE_PKTS) file_size = FILE_QUEUE_PKTS;
}
udp_mutex.lock();
udp_size -= UDP_THRESHOLD; // we've written this amount out
udp_mutex.unlock();
//file_out.flush();
file_mutex.unlock();
//LOGD("Written UDP overflow at %d of %d blocks file size %d",
// udp_index, written, file_size);
}
char *FFIOBufferManager2::get_udp_buffer(int index) {
if (index < 0 || index >= UDP_QUEUE_SIZE) return nullptr;
return ((char*)udp_buffer + (index * PKT_SIZE7));
}
/*
* The avio_read and avio_seek now work on either 188 byte alignment or
* byte alignment for the benefit of ffmpeg - byte positioning at the moment
*
* The file_mutex allows for either a read or write operation at a time
*/
int FFIOBufferManager2::avio_read(void *ptr, uint8_t *buff, int buf_size) {
FFIOBufferManager2 *io = (FFIOBufferManager2*)ptr;
return io->avio_read_run(buff, buf_size);
}
int64_t FFIOBufferManager2::avio_seek(void *ptr, int64_t pos, int whence) {
FFIOBufferManager2 *io = (FFIOBufferManager2*)ptr;
return io->avio_seek_run(pos, whence);
}
int FFIOBufferManager2::avio_read_run(uint8_t *buf, int buf_size) {
file_mutex.lock();
udp_mutex.lock();
int64_t cur_udp_write_pos = (int64_t) udp_write_pos * PKT_SIZE7;
int64_t cur_udp_size = (int64_t) udp_size * PKT_SIZE7;
int64_t cur_file_write_pos = (int64_t) file_write_pos * PKT_SIZE7;
int64_t cur_file_size = (int64_t) file_size * PKT_SIZE7;
int64_t cur_avio_read_offset = avio_read_offset; // already int64_t (under the udp_mutex)
udp_mutex.unlock();
if (cur_avio_read_offset < (AVIO_THRESHOLD * 4) * PKT_SIZE7) {
file_mutex.unlock();
return 0;
}
int64_t udp_buffer_max = (int64_t) (UDP_QUEUE_SIZE * PKT_SIZE7);
int64_t file_buffer_max = (int64_t) (FILE_QUEUE_PKTS * PKT_SIZE7);
uint8_t *ptr_udp_buffer = (uint8_t*)udp_buffer;
int cur_written = 0;
int file_reads = 0, udp_reads = 0; // for debugging
int64_t cur_file_offset = cur_file_write_pos - cur_udp_size - cur_avio_read_offset;
while (cur_file_offset < 0) cur_file_offset += file_buffer_max;
if (cur_file_offset >= 0) {
file_in.seekg(cur_file_offset);
while (//cur_avio_read_offset > 0
cur_avio_read_offset > cur_udp_size
&& cur_written < buf_size) { // read from file first
file_in.read(&avio_buffer[cur_written], PKT_SIZE); // get 1 or 188 byte/s
cur_file_offset+=PKT_SIZE;
if (cur_file_offset >= file_buffer_max) { // back to file beginning
cur_file_offset = 0;
file_in.seekg(0);
}
cur_avio_read_offset-=PKT_SIZE;
cur_written+=PKT_SIZE;
file_reads+=PKT_SIZE;
}
}
int64_t cur_udp_offset = (cur_udp_write_pos - cur_avio_read_offset);
if (cur_udp_offset < 0) cur_udp_offset += udp_buffer_max;
while (cur_avio_read_offset > AVIO_THRESHOLD * PKT_SIZE7
&& cur_avio_read_offset <= cur_udp_size
&& cur_written < buf_size) { // read the rest from udp buffer
buf[cur_written] = ptr_udp_buffer[cur_udp_offset]; // get byte
cur_udp_offset = (cur_udp_offset + 1) % udp_buffer_max;
if (cur_udp_offset == 0) LOGD("AVIO UDP BUFFER to start");
cur_avio_read_offset--;
cur_written++;
udp_reads++;
}
udp_mutex.lock();
avio_read_offset -= cur_written;
udp_mutex.unlock();
file_mutex.unlock();
if (cur_written) {
LOGD("AVIO_READ: Written %d of %d, avio_offset %lld, file reads %d, udp reads %d, udp offset %lld, file offset %lld, file size %lld",
cur_written, buf_size,
cur_avio_read_offset,
file_reads, udp_reads,
cur_udp_write_pos, cur_file_write_pos, cur_file_size);
}
return cur_written;
}
int64_t FFIOBufferManager2::avio_seek_run(int64_t pos, int whence) {
// SEEK_SET(0), SEEK_CUR(1), SEEK_END(2), AVSEEK_SIZE
int64_t new_pos = -1;
int64_t full_length = (udp_size + file_size) * PKT_SIZE7;
switch (whence) {
case AVSEEK_SIZE:
LOGD("AVSEEK_SIZE pos %lld", pos);
break;
case SEEK_SET:
LOGD("AVSEEK_SET pos %lld", pos);
if (pos > full_length) new_pos = full_length;
else new_pos = full_length - pos;
break;
case SEEK_CUR:
LOGD("AVSEEK_CUR pos %lld", pos);
break;
case SEEK_END:
LOGD("AVSEEK_END pos %lld", pos);
new_pos = pos;
break;
default:
LOGD("UNKNOWN AVIO SEEK whence %d pos %lld", whence, pos);
break;
}
if (new_pos >= 0) {
udp_mutex.lock();
new_pos = (new_pos / PKT_SIZE) * PKT_SIZE; // align to packet boundary
avio_read_offset = new_pos;
//file_out.seekg(full_length - new_pos);
udp_mutex.unlock();
return full_length - new_pos;
}
return -1;
}
FFIOBufferManager2::~FFIOBufferManager2() {
if (avioContext) ;// TODO whoops
quit = true;
if (udp_thread.joinable()) udp_thread.join();
if (file_thread.joinable()) file_thread.join();
}
void FFIOBufferManager2::get_size_and_pos(int64_t *size, int64_t *pos) {
file_mutex.lock();
udp_mutex.lock();
*size = (udp_size + file_size) * PKT_SIZE7;
*pos = *size - avio_read_offset;
udp_mutex.unlock();
file_mutex.unlock();
}It’ll play for a few seconds before any of the glitches start to appear. I have checked against the udp_buffer and the avio_buffer, but my suspicions lie with one of two things :
- Reading and writing to the file.
- the
avio_read
method is wrong.
Has anybody got any input as to why this is occurring ? Any thoughts would be greatly appreciated.
If you need any more information I’ll be glad to provide more details.
EDIT : Seeking now actually moves to any point within the stream, but now doesn’t read from the file recording. Although that’s only a minor issue at the moment.
The main two issues still stand, frame rate drops dramatically and the glitches after approximately 8 seconds.