Support video capture during playback
[platform/core/multimedia/esplusplayer.git] / src / esplusplayer / include_internal / esplayer / decoded_pkt_list.h
1 //
2 // @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
3 //
4
5 #ifndef __PLUSPLAYER_SRC_ESPLAYER_DECODED_PACKET_LIST_H__
6 #define __PLUSPLAYER_SRC_ESPLAYER_DECODED_PACKET_LIST_H__
7
8 #include <tbm_surface.h>
9
10 #include <algorithm>
11 #include <functional>
12 #include <list>
13 #include <memory>
14 #include <gst/gst.h>
15
16 #include "core/utils/plusplayer_log.h"
17 #include "plusplayer/types/buffer.h"
18
19 namespace {
20 void DecodedPacketDeleter(esplusplayer_decoded_video_packet* packet) {
21   if (packet == nullptr) return;
22   // LOG_DEBUG("packet[%p] deleted", packet);
23   if(packet->private_data) { // hw dec
24     gst_buffer_unref((GstBuffer *)packet->private_data);
25     packet->private_data = nullptr;
26   }
27   if(packet->surface_data) {
28     tbm_surface_destroy(static_cast<tbm_surface_h>(packet->surface_data));
29     packet->surface_data = nullptr;
30   }
31 }
32 }  // namespace
33
34 namespace plusplayer {
35 struct DecodedPacketManagerInterface {
36   virtual ~DecodedPacketManagerInterface() = default;
37   virtual bool TryToAdd(esplusplayer_decoded_video_packet* packet) = 0;
38   virtual void Remove(esplusplayer_decoded_video_packet* packet) = 0;
39   virtual void Clear() = 0;
40   virtual void GetFreeTbmSurface(void** ptr, bool is_scale_change) = 0;
41 };
42 struct CmaBufferInfo {
43   void* tbm_surf = nullptr;
44   bool tbm_is_free = true;
45   bool destroy_flag = false;
46 };
47
48 class AbstractDecodedPacketList : public DecodedPacketManagerInterface {
49  public:
50   explicit AbstractDecodedPacketList() = default;
51   virtual ~AbstractDecodedPacketList() = default;
52   using DecodedPacketPtr =
53       std::unique_ptr<esplusplayer_decoded_video_packet,
54                       std::function<void(esplusplayer_decoded_video_packet*)>>;
55
56  public:
57   virtual bool TryToAdd(esplusplayer_decoded_video_packet* packet) override {
58     if (packet == nullptr) {
59       LOG_ERROR("packet is nullptr");
60       return false;
61     }
62     std::unique_lock<std::mutex> lk(mtx_);
63     auto pkt_ptr = DecodedPacketPtr(
64         packet, [this](esplusplayer_decoded_video_packet* pkt) {
65           DecodedPacketDeleter(pkt);
66           delete pkt;
67         });
68     if (IsAvailableInternal() == false) {
69       LOG_ERROR("not available to add a packet");
70       return false;
71     }
72     // LOG_DEBUG("packet[%p] added", packet);
73     list_.emplace_back(std::move(pkt_ptr));
74     return true;
75   }
76   virtual void Remove(esplusplayer_decoded_video_packet* packet) override {
77     if (packet == nullptr) return;
78     std::unique_lock<std::mutex> lk(mtx_);
79     list_.remove_if([&packet](const DecodedPacketPtr& cur) {
80       if (cur.get() == packet) return true;
81       return false;
82     });
83   }
84   virtual void Clear() override {
85     std::unique_lock<std::mutex> lk(mtx_);
86     LOG_DEBUG("all packets are cleared");
87     list_.clear();
88   }
89
90   virtual void GetFreeTbmSurface(void** ptr, bool is_scale_change) override {
91     return;
92   }
93
94  protected:
95   const std::list<DecodedPacketPtr>& GetList() { return list_; }
96
97  protected:
98   virtual bool IsAvailableInternal() = 0;
99   virtual void DecodedPacketDeleter(
100       esplusplayer_decoded_video_packet* packet) = 0;
101
102  protected:
103   std::mutex mtx_;
104   std::list<DecodedPacketPtr> list_;
105 };
106
107 class DecodedReferencePacketList : public AbstractDecodedPacketList {
108  public:
109   explicit DecodedReferencePacketList() { LOG_DEBUG("created"); }
110   virtual ~DecodedReferencePacketList() { LOG_DEBUG("destroyed"); }
111
112  protected:
113   virtual bool IsAvailableInternal() override {
114     if (GetList().size() > kMaxAvailableSize_) return false;
115     return true;
116   }
117   virtual void DecodedPacketDeleter(
118       esplusplayer_decoded_video_packet* packet) override {
119     ::DecodedPacketDeleter(packet);
120   }
121
122  private:
123   const std::uint32_t kMaxAvailableSize_ = 5;
124 };
125
126 class DecodedCopiedPacketList : public AbstractDecodedPacketList {
127  public:
128   explicit DecodedCopiedPacketList() { LOG_DEBUG("created"); }
129   virtual ~DecodedCopiedPacketList() { LOG_DEBUG("destroyed"); }
130
131  protected:
132   virtual bool IsAvailableInternal() override { return true; }
133   virtual void DecodedPacketDeleter(
134       esplusplayer_decoded_video_packet* packet) override {
135     ::DecodedPacketDeleter(packet);
136   }
137 };
138
139 class ManualDecodedCopiedPacketList : public DecodedPacketManagerInterface {
140  public:
141   using Handler = std::function<bool(esplusplayer_decoded_video_packet*)>;
142   explicit ManualDecodedCopiedPacketList(Handler handler) : handler_(handler) {
143     LOG_DEBUG("created");
144   }
145   virtual ~ManualDecodedCopiedPacketList() { LOG_DEBUG("destroyed"); }
146
147  protected:
148   virtual bool TryToAdd(esplusplayer_decoded_video_packet* packet) {
149     return false;
150   }
151   virtual void Clear() {}
152   virtual void GetFreeTbmSurface(void** ptr, bool is_scale_change) {}
153
154   virtual void Remove(esplusplayer_decoded_video_packet* packet) {
155     if (handler_(packet) == false) {
156       LOG_ERROR("packet return failed");
157     }
158   }
159
160  private:
161   Handler handler_;
162 };
163 class DecodedScaledPacketList : public AbstractDecodedPacketList {
164  public:
165   explicit DecodedScaledPacketList() { LOG_DEBUG("created"); }
166   virtual ~DecodedScaledPacketList() { LOG_DEBUG("destroyed"); }
167   virtual void GetFreeTbmSurface(void** ptr, bool is_scale_change) {
168     std::unique_lock<std::mutex> lk(mtx_);
169     if (is_scale_change) {
170       for (std::vector<CmaBufferInfo>::iterator it = tbm_mgr_.begin();
171            it != tbm_mgr_.end();) {
172         if (it->tbm_is_free == true) {
173           LOG_ERROR("scale size changed, destroy the free tbm %p",
174                     it->tbm_surf);
175           tbm_surface_destroy(static_cast<tbm_surface_h>(it->tbm_surf));
176           it = tbm_mgr_.erase(it);
177         } else {
178           LOG_ERROR("scale size changed, using tbm will be destroy later%p",
179                     it->tbm_surf);
180           it->destroy_flag = true;
181           it++;
182         }
183       }
184       *ptr = nullptr;
185     } else {
186       auto tbm_is_free = [](const CmaBufferInfo& item) -> bool {
187         return item.tbm_is_free == true;
188       };
189       auto target = std::find_if(tbm_mgr_.begin(), tbm_mgr_.end(), tbm_is_free);
190       if (target != tbm_mgr_.end()) {
191         *ptr = target->tbm_surf;
192       }
193     }
194     return;
195   }
196
197   virtual bool TryToAdd(esplusplayer_decoded_video_packet* packet) override {
198     if (packet == nullptr) {
199       LOG_ERROR("packet is nullptr");
200       return false;
201     }
202     std::unique_lock<std::mutex> lk(mtx_);
203     auto pkt_ptr = DecodedPacketPtr(
204         packet, [this](esplusplayer_decoded_video_packet* pkt) {
205           DecodedPacketDeleter(pkt);
206           delete pkt;
207         });
208     if (IsAvailableInternal() == false) {
209       LOG_ERROR("not available to add a packet");
210       return false;
211     }
212     // traverse tbm_mgr to find the same tbm surf,if find, change that,if not,
213     // new one and add to vector.
214     void* tbm_ptr = packet->surface_data;
215     auto has_tbm = [tbm_ptr](const CmaBufferInfo& item) -> bool {
216       return item.tbm_surf == tbm_ptr;
217     };
218     auto target = std::find_if(tbm_mgr_.begin(), tbm_mgr_.end(), has_tbm);
219     if (target == tbm_mgr_.end()) {
220       CmaBufferInfo tmp_tbm_buffer;
221       tmp_tbm_buffer.tbm_surf = packet->surface_data;
222       tmp_tbm_buffer.tbm_is_free = false;
223       tmp_tbm_buffer.destroy_flag = false;
224       tbm_mgr_.push_back(tmp_tbm_buffer);
225       LOG_ERROR("add tbm surface %p to list", tmp_tbm_buffer.tbm_surf);
226     } else {
227       target->tbm_is_free = false;
228     }
229     list_.emplace_back(std::move(pkt_ptr));
230     return true;
231   }
232
233   virtual void Remove(esplusplayer_decoded_video_packet* packet) override {
234     if (packet == nullptr) return;
235     std::unique_lock<std::mutex> lk(mtx_);
236     // LOG_ERROR("Remove pkt %p ", packet->surface_data);
237     // before remove packet, set the tbm surf free.
238     void* tbm_ptr = packet->surface_data;
239     auto has_tbm = [tbm_ptr](const CmaBufferInfo& item) -> bool {
240       return item.tbm_surf == tbm_ptr;
241     };
242     auto target = std::find_if(tbm_mgr_.begin(), tbm_mgr_.end(), has_tbm);
243     if (target != tbm_mgr_.end()) {
244       if (target->destroy_flag == true) {
245         LOG_ERROR("destroy tbm surface %p", target->tbm_surf);
246         tbm_surface_destroy(static_cast<tbm_surface_h>(target->tbm_surf));
247         tbm_mgr_.erase(target);
248       } else {
249         target->tbm_is_free = true;
250       }
251     }
252     list_.remove_if([&packet](const DecodedPacketPtr& cur) {
253       if (cur.get() == packet) return true;
254       return false;
255     });
256   }
257
258   virtual void Clear() override {
259     std::unique_lock<std::mutex> lk(mtx_);
260     LOG_DEBUG("all packets are cleared");
261     list_.clear();
262     for (auto& iter : tbm_mgr_) {
263       LOG_ERROR("destroy tbm buffer in list %p", iter.tbm_surf);
264       tbm_surface_destroy(static_cast<tbm_surface_h>(iter.tbm_surf));
265     }
266     std::vector<CmaBufferInfo> tmp;
267     tbm_mgr_.swap(tmp);
268   }
269
270  protected:
271   virtual bool IsAvailableInternal() override {
272     if (GetList().size() > kMaxAvailableSize_) return false;
273     return true;
274   }
275
276   virtual void DecodedPacketDeleter(
277       esplusplayer_decoded_video_packet* packet) override {
278     // redesign, when pkt list is full, which means new tbm ptr can't add, so
279     // destroy it after create in trackrender.
280     if (GetList().size() > kMaxAvailableSize_) {
281       if (packet == nullptr || packet->surface_data == nullptr) return;
282       // only destroy the tbm surface new created but not added in tbm list
283       void* tbm_ptr = packet->surface_data;
284       auto has_tbm = [tbm_ptr](const CmaBufferInfo& item) -> bool {
285         return item.tbm_surf == tbm_ptr;
286       };
287       auto target = std::find_if(tbm_mgr_.begin(), tbm_mgr_.end(), has_tbm);
288       if (target == tbm_mgr_.end()) {
289         LOG_ERROR("tbm_surface_destroy[%p] deleted", packet->surface_data);
290         tbm_surface_destroy(static_cast<tbm_surface_h>(packet->surface_data));
291         packet->surface_data = NULL;
292       }
293     }
294   }
295
296  private:
297   const std::uint32_t kMaxAvailableSize_ = 5;
298   std::vector<CmaBufferInfo> tbm_mgr_;
299 };
300 }  // namespace plusplayer
301
302 #endif  // __PLUSPLAYER_SRC_ESPLAYER_DECODED_PACKET_LIST_H__