mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
osg-ffmpeg-videoplayer: Fix crash on ARM
osg-ffmpeg-videoplayer handled frame allocation incorrectly. It used a `vector<uint8_t>` as its buffer, meaning the addresses could did not respect alignment. Instead, changes it to use `AVFrame` as buffers, allocated via `av_image_alloc`. We also now only allocate the buffer once, instead of on every frame, which should improve the framerate of videos. Fixes the following crash on startup on ARM: > Invalid address alignment (signal 7) Fixes #5807
This commit is contained in:
parent
2bfee281fd
commit
b7076549a3
2 changed files with 33 additions and 15 deletions
45
extern/osg-ffmpeg-videoplayer/videostate.cpp
vendored
45
extern/osg-ffmpeg-videoplayer/videostate.cpp
vendored
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -49,7 +50,7 @@ VideoState::VideoState()
|
||||||
, av_sync_type(AV_SYNC_DEFAULT)
|
, av_sync_type(AV_SYNC_DEFAULT)
|
||||||
, audio_st(nullptr)
|
, audio_st(nullptr)
|
||||||
, video_st(nullptr), frame_last_pts(0.0)
|
, video_st(nullptr), frame_last_pts(0.0)
|
||||||
, video_clock(0.0), sws_context(nullptr), rgbaFrame(nullptr), pictq_size(0)
|
, video_clock(0.0), sws_context(nullptr), pictq_size(0)
|
||||||
, pictq_rindex(0), pictq_windex(0)
|
, pictq_rindex(0), pictq_windex(0)
|
||||||
, mSeekRequested(false)
|
, mSeekRequested(false)
|
||||||
, mSeekPos(0)
|
, mSeekPos(0)
|
||||||
|
@ -220,7 +221,7 @@ void VideoState::video_display(VideoPicture *vp)
|
||||||
osg::ref_ptr<osg::Image> image = new osg::Image;
|
osg::ref_ptr<osg::Image> image = new osg::Image;
|
||||||
|
|
||||||
image->setImage(this->video_ctx->width, this->video_ctx->height,
|
image->setImage(this->video_ctx->width, this->video_ctx->height,
|
||||||
1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, &vp->data[0], osg::Image::NO_DELETE);
|
1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, vp->rgbaFrame->data[0], osg::Image::NO_DELETE);
|
||||||
|
|
||||||
mTexture->setImage(image);
|
mTexture->setImage(image);
|
||||||
}
|
}
|
||||||
|
@ -308,11 +309,8 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts)
|
||||||
}
|
}
|
||||||
|
|
||||||
vp->pts = pts;
|
vp->pts = pts;
|
||||||
vp->data.resize(this->video_ctx->width * this->video_ctx->height * 4);
|
|
||||||
|
|
||||||
uint8_t *dst[4] = { &vp->data[0], nullptr, nullptr, nullptr };
|
|
||||||
sws_scale(this->sws_context, pFrame->data, pFrame->linesize,
|
sws_scale(this->sws_context, pFrame->data, pFrame->linesize,
|
||||||
0, this->video_ctx->height, dst, this->rgbaFrame->linesize);
|
0, this->video_ctx->height, vp->rgbaFrame->data, vp->rgbaFrame->linesize);
|
||||||
|
|
||||||
// now we inform our display thread that we have a pic ready
|
// now we inform our display thread that we have a pic ready
|
||||||
this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_ARRAY_SIZE;
|
this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_ARRAY_SIZE;
|
||||||
|
@ -364,9 +362,6 @@ public:
|
||||||
|
|
||||||
pFrame = av_frame_alloc();
|
pFrame = av_frame_alloc();
|
||||||
|
|
||||||
self->rgbaFrame = av_frame_alloc();
|
|
||||||
av_image_alloc(self->rgbaFrame->data, self->rgbaFrame->linesize, self->video_ctx->width, self->video_ctx->height, AV_PIX_FMT_RGBA, 1);
|
|
||||||
|
|
||||||
while(self->videoq.get(packet, self) >= 0)
|
while(self->videoq.get(packet, self) >= 0)
|
||||||
{
|
{
|
||||||
if(packet->data == flush_pkt.data)
|
if(packet->data == flush_pkt.data)
|
||||||
|
@ -407,10 +402,7 @@ public:
|
||||||
|
|
||||||
av_packet_unref(packet);
|
av_packet_unref(packet);
|
||||||
|
|
||||||
av_free(pFrame);
|
av_frame_free(&pFrame);
|
||||||
|
|
||||||
av_freep(&self->rgbaFrame->data[0]);
|
|
||||||
av_free(self->rgbaFrame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -630,6 +622,25 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocate RGBA frame queue.
|
||||||
|
for (std::size_t i = 0; i < VIDEO_PICTURE_ARRAY_SIZE; ++i) {
|
||||||
|
AVFrame *frame = av_frame_alloc();
|
||||||
|
if (frame == nullptr) {
|
||||||
|
std::cerr << "av_frame_alloc failed" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr AVPixelFormat kPixFmt = AV_PIX_FMT_RGBA;
|
||||||
|
frame->format = kPixFmt;
|
||||||
|
frame->width = this->video_ctx->width;
|
||||||
|
frame->height = this->video_ctx->height;
|
||||||
|
if (av_image_alloc(frame->data, frame->linesize, frame->width, frame->height, kPixFmt, 1) < 0) {
|
||||||
|
std::cerr << "av_image_alloc failed" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
this->pictq[i].rgbaFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
this->video_thread.reset(new VideoThread(this));
|
this->video_thread.reset(new VideoThread(this));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -771,6 +782,14 @@ void VideoState::deinit()
|
||||||
mTexture->setImage(nullptr);
|
mTexture->setImage(nullptr);
|
||||||
mTexture = nullptr;
|
mTexture = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dellocate RGBA frame queue.
|
||||||
|
for (std::size_t i = 0; i < VIDEO_PICTURE_ARRAY_SIZE; ++i) {
|
||||||
|
if (this->pictq[i].rgbaFrame == nullptr) continue;
|
||||||
|
av_freep(&this->pictq[i].rgbaFrame->data[0]);
|
||||||
|
av_frame_free(&this->pictq[i].rgbaFrame);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double VideoState::get_external_clock()
|
double VideoState::get_external_clock()
|
||||||
|
|
3
extern/osg-ffmpeg-videoplayer/videostate.hpp
vendored
3
extern/osg-ffmpeg-videoplayer/videostate.hpp
vendored
|
@ -95,7 +95,7 @@ struct VideoPicture {
|
||||||
VideoPicture() : pts(0.0)
|
VideoPicture() : pts(0.0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
std::vector<uint8_t> data;
|
AVFrame* rgbaFrame = nullptr;
|
||||||
double pts;
|
double pts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -160,7 +160,6 @@ struct VideoState {
|
||||||
PacketQueue videoq;
|
PacketQueue videoq;
|
||||||
SwsContext* sws_context;
|
SwsContext* sws_context;
|
||||||
VideoPicture pictq[VIDEO_PICTURE_ARRAY_SIZE];
|
VideoPicture pictq[VIDEO_PICTURE_ARRAY_SIZE];
|
||||||
AVFrame* rgbaFrame; // used as buffer for the frame converted from its native format to RGBA
|
|
||||||
int pictq_size, pictq_rindex, pictq_windex;
|
int pictq_size, pictq_rindex, pictq_windex;
|
||||||
std::mutex pictq_mutex;
|
std::mutex pictq_mutex;
|
||||||
std::condition_variable pictq_cond;
|
std::condition_variable pictq_cond;
|
||||||
|
|
Loading…
Reference in a new issue