1 /*
2 * Copyright (C) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <arpa/inet.h>
16 #include <sys/time.h>
17 #include <utility>
18 #include "videodec_sample.h"
19 using namespace OHOS;
20 using namespace OHOS::Media;
21 using namespace std;
22 namespace {
23 const string MIME_TYPE = "video/mp4v-es";
24 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
25 constexpr int64_t NANOS_IN_MICRO = 1000L;
26 constexpr uint32_t PREREAD_BUFFER_SIZE = 0.1 * 1024 * 1024;
27 constexpr uint8_t MPEG4_FRAME_HEAD[] = {0x00, 0x00, 0x01, 0xb6};
28 constexpr uint8_t MPEG4_SEQUENCE_HEAD[] = {0x00, 0x00, 0x01, 0xb0};
29 constexpr uint32_t START_CODE_SIZE = 4;
30 constexpr uint32_t MAX_WIDTH = 4000;
31 constexpr uint32_t MAX_HEIGHT = 3000;
32 constexpr uint32_t MAX_NALU_SIZE = MAX_WIDTH * MAX_HEIGHT << 1;
33 VDecFuzzSample *g_decSample = nullptr;
34
35 bool g_fuzzError = false;
36
clearIntqueue(std::queue<uint32_t> & q)37 void clearIntqueue(std::queue<uint32_t> &q)
38 {
39 std::queue<uint32_t> empty;
40 swap(empty, q);
41 }
42
clearBufferqueue(std::queue<OH_AVCodecBufferAttr> & q)43 void clearBufferqueue(std::queue<OH_AVCodecBufferAttr> &q)
44 {
45 std::queue<OH_AVCodecBufferAttr> empty;
46 swap(empty, q);
47 }
48
clearAvBufferQueue(std::queue<OH_AVMemory * > & q)49 void clearAvBufferQueue(std::queue<OH_AVMemory *> &q)
50 {
51 std::queue<OH_AVMemory *> empty;
52 swap(empty, q);
53 }
54 } // namespace
55
56 class TestConsumerListener : public IBufferConsumerListener {
57 public:
TestConsumerListener(sptr<Surface> cs)58 TestConsumerListener(sptr<Surface> cs) : cs(cs) {};
~TestConsumerListener()59 ~TestConsumerListener() {}
OnBufferAvailable()60 void OnBufferAvailable() override
61 {
62 sptr<SurfaceBuffer> buffer;
63 int32_t flushFence;
64 cs->AcquireBuffer(buffer, flushFence, timestamp, damage);
65
66 cs->ReleaseBuffer(buffer, -1);
67 }
68
69 private:
70 int64_t timestamp = 0;
71 Rect damage = {};
72 sptr<Surface> cs {nullptr};
73 };
74
~VDecFuzzSample()75 VDecFuzzSample::~VDecFuzzSample()
76 {
77 Release();
78 }
79
VdecError(OH_AVCodec * codec,int32_t errorCode,void * userData)80 void VdecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
81 {
82 VDecSignal *signal = static_cast<VDecSignal *>(userData);
83 if (signal == nullptr) {
84 return;
85 }
86 cout << "Error errorCode=" << errorCode << endl;
87 g_fuzzError = true;
88 g_decSample->isRunning_.store(false);
89 signal->inCond_.notify_all();
90 }
91
VdecFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)92 void VdecFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
93 {
94 cout << "Format Changed" << endl;
95 int32_t currentWidth = 0;
96 int32_t currentHeight = 0;
97 OH_AVFormat_GetIntValue(format, OH_MD_KEY_WIDTH, ¤tWidth);
98 OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, ¤tHeight);
99 g_decSample->defaultWidth = currentWidth;
100 g_decSample->defaultHeight = currentHeight;
101 }
102
VdecInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)103 void VdecInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
104 {
105 VDecSignal *signal = static_cast<VDecSignal *>(userData);
106 if (signal == nullptr) {
107 return;
108 }
109 unique_lock<mutex> lock(signal->inMutex_);
110 signal->inIdxQueue_.push(index);
111 signal->inBufferQueue_.push(data);
112 signal->inCond_.notify_all();
113 }
114
VdecOutputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)115 void VdecOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
116 void *userData)
117 {
118 VDecSignal *signal = static_cast<VDecSignal *>(userData);
119 if (signal == nullptr) {
120 return;
121 }
122 unique_lock<mutex> lock(signal->outMutex_);
123 signal->outIdxQueue_.push(index);
124 signal->attrQueue_.push(*attr);
125 signal->outBufferQueue_.push(data);
126 signal->outCond_.notify_all();
127 if (g_decSample->isSurfMode) {
128 OH_VideoDecoder_RenderOutputData(codec, index);
129 } else {
130 OH_VideoDecoder_FreeOutputData(codec, index);
131 }
132 }
133
GetSystemTimeUs()134 int64_t VDecFuzzSample::GetSystemTimeUs()
135 {
136 struct timespec now;
137 (void)clock_gettime(CLOCK_BOOTTIME, &now);
138 int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
139 return nanoTime / NANOS_IN_MICRO;
140 }
141
ConfigureVideoDecoder()142 int32_t VDecFuzzSample::ConfigureVideoDecoder()
143 {
144 if (isSurfMode) {
145 cs = Surface::CreateSurfaceAsConsumer();
146 sptr<IBufferConsumerListener> listener = new TestConsumerListener(cs);
147 cs->RegisterConsumerListener(listener);
148 auto p = cs->GetProducer();
149 ps = Surface::CreateSurfaceAsProducer(p);
150 nativeWindow = CreateNativeWindowFromSurface(&ps);
151 OH_VideoDecoder_SetSurface(vdec_, nativeWindow);
152 }
153 OH_AVFormat *format = OH_AVFormat_Create();
154 if (format == nullptr) {
155 cout << "Fatal: Failed to create format" << endl;
156 return AV_ERR_UNKNOWN;
157 }
158 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth);
159 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight);
160 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, defaultFrameRate);
161 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, defaultRotation);
162 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, defaultPixelFormat);
163 int ret = OH_VideoDecoder_Configure(vdec_, format);
164 OH_AVFormat_Destroy(format);
165 return ret;
166 }
167
RunVideoDec(string codeName)168 int32_t VDecFuzzSample::RunVideoDec(string codeName)
169 {
170 int err = CreateVideoDecoder(codeName);
171 if (err != AV_ERR_OK) {
172 cout << "Failed to create video decoder" << endl;
173 return err;
174 }
175 err = ConfigureVideoDecoder();
176 if (err != AV_ERR_OK) {
177 cout << "Failed to configure video decoder" << endl;
178 Release();
179 return err;
180 }
181 err = SetVideoDecoderCallback();
182 if (err != AV_ERR_OK) {
183 cout << "Failed to setCallback" << endl;
184 Release();
185 return err;
186 }
187 err = StartVideoDecoder();
188 if (err != AV_ERR_OK) {
189 cout << "Failed to start video decoder" << endl;
190 Release();
191 return err;
192 }
193 return err;
194 }
195
SetVideoDecoderCallback()196 int32_t VDecFuzzSample::SetVideoDecoderCallback()
197 {
198 signal_ = new VDecSignal();
199 if (signal_ == nullptr) {
200 cout << "Failed to new VDecSignal" << endl;
201 return AV_ERR_UNKNOWN;
202 }
203
204 cb_.onError = VdecError;
205 cb_.onStreamChanged = VdecFormatChanged;
206 cb_.onNeedInputData = VdecInputDataReady;
207 cb_.onNeedOutputData = VdecOutputDataReady;
208 return OH_VideoDecoder_SetCallback(vdec_, cb_, static_cast<void *>(signal_));
209 }
210
ReleaseInFile()211 void VDecFuzzSample::ReleaseInFile()
212 {
213 if (inFile_ != nullptr) {
214 if (inFile_->is_open()) {
215 inFile_->close();
216 }
217 inFile_.reset();
218 inFile_ = nullptr;
219 }
220 }
221
StopInloop()222 void VDecFuzzSample::StopInloop()
223 {
224 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
225 unique_lock<mutex> lock(signal_->inMutex_);
226 clearIntqueue(signal_->inIdxQueue_);
227 signal_->inCond_.notify_all();
228 lock.unlock();
229
230 inputLoop_->join();
231 inputLoop_.reset();
232 }
233 }
234
StartVideoDecoder()235 int32_t VDecFuzzSample::StartVideoDecoder()
236 {
237 int ret = OH_VideoDecoder_Start(vdec_);
238 if (ret != AV_ERR_OK) {
239 cout << "Failed to start codec" << endl;
240 return ret;
241 }
242
243 isRunning_.store(true);
244
245 inFile_ = make_unique<ifstream>();
246 if (inFile_ == nullptr) {
247 isRunning_.store(false);
248 (void)OH_VideoDecoder_Stop(vdec_);
249 return AV_ERR_UNKNOWN;
250 }
251 inFile_->open(inpDir, ios::in | ios::binary);
252 if (!inFile_->is_open()) {
253 cout << "open input file failed" << endl;
254 isRunning_.store(false);
255 (void)OH_VideoDecoder_Stop(vdec_);
256 inFile_->close();
257 inFile_.reset();
258 inFile_ = nullptr;
259 return AV_ERR_UNKNOWN;
260 }
261
262 inputLoop_ = make_unique<thread>(&VDecFuzzSample::InputFuncAVCC, this);
263 if (inputLoop_ == nullptr) {
264 cout << "Failed to create input loop" << endl;
265 isRunning_.store(false);
266 (void)OH_VideoDecoder_Stop(vdec_);
267 ReleaseInFile();
268 return AV_ERR_UNKNOWN;
269 }
270 return AV_ERR_OK;
271 }
272
CreateVideoDecoder(string codeName)273 int32_t VDecFuzzSample::CreateVideoDecoder(string codeName)
274 {
275 vdec_ = OH_VideoDecoder_CreateByName("aabbcc");
276 if (vdec_) {
277 OH_VideoDecoder_Destroy(vdec_);
278 vdec_ = nullptr;
279 }
280 OH_AVCodec *tmpDec = OH_VideoDecoder_CreateByMime("aabbcc");
281 if (tmpDec) {
282 OH_VideoDecoder_Destroy(tmpDec);
283 tmpDec = nullptr;
284 }
285 tmpDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
286 if (tmpDec) {
287 OH_VideoDecoder_Destroy(tmpDec);
288 tmpDec = nullptr;
289 }
290 vdec_ = OH_VideoDecoder_CreateByName(codeName.c_str());
291 g_decSample = this;
292 return vdec_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
293 }
294
WaitForEOS()295 void VDecFuzzSample::WaitForEOS()
296 {
297 if (inputLoop_ && inputLoop_->joinable()) {
298 inputLoop_->join();
299 }
300 }
301
PtrStep(uint32_t & bufferSize,unsigned char ** pBuffer,uint32_t size)302 void VDecFuzzSample::PtrStep(uint32_t &bufferSize, unsigned char **pBuffer, uint32_t size)
303 {
304 pPrereadBuffer_ += size;
305 bufferSize += size;
306 *pBuffer += size;
307 }
308
PtrStepExtraRead(uint32_t & bufferSize,unsigned char ** pBuffer)309 void VDecFuzzSample::PtrStepExtraRead(uint32_t &bufferSize, unsigned char **pBuffer)
310 {
311 bufferSize -= START_CODE_SIZE;
312 *pBuffer -= START_CODE_SIZE;
313 pPrereadBuffer_ = 0;
314 }
315
GetBufferSize()316 void VDecFuzzSample::GetBufferSize()
317 {
318 auto pBuffer = mpegUnit_->data();
319 uint32_t bufferSize = 0;
320 mpegUnit_->resize(MAX_NALU_SIZE);
321 do {
322 auto pos1 = std::search(prereadBuffer_.get() + pPrereadBuffer_ + START_CODE_SIZE,
323 prereadBuffer_.get() + prereadBufferSize_, std::begin(MPEG4_FRAME_HEAD), std::end(MPEG4_FRAME_HEAD));
324 uint32_t size1 = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos1);
325 auto pos2 = std::search(prereadBuffer_.get() + pPrereadBuffer_, prereadBuffer_.get() +
326 pPrereadBuffer_ + size1, std::begin(MPEG4_SEQUENCE_HEAD), std::end(MPEG4_SEQUENCE_HEAD));
327 uint32_t size = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos2);
328 if (size == 0) {
329 auto pos3 = std::search(prereadBuffer_.get() + pPrereadBuffer_ + size1 + START_CODE_SIZE,
330 prereadBuffer_.get() + prereadBufferSize_, std::begin(MPEG4_FRAME_HEAD), std::end(MPEG4_FRAME_HEAD));
331 uint32_t size2 = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos3);
332 if (memcpy_s(pBuffer, size2, prereadBuffer_.get() + pPrereadBuffer_, size2) != EOK) {
333 return;
334 }
335 PtrStep(bufferSize, &pBuffer, size2);
336 if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
337 break;
338 }
339 } else if (size1 > size) {
340 if (memcpy_s(pBuffer, size, prereadBuffer_.get() + pPrereadBuffer_, size) != EOK) {
341 return;
342 }
343 PtrStep(bufferSize, &pBuffer, size);
344 if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
345 break;
346 }
347 } else {
348 if (memcpy_s(pBuffer, size1, prereadBuffer_.get() + pPrereadBuffer_, size1) != EOK) {
349 return;
350 }
351 PtrStep(bufferSize, &pBuffer, size1);
352 if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
353 break;
354 }
355 }
356 inFile_->read(reinterpret_cast<char *>(prereadBuffer_.get() + START_CODE_SIZE), PREREAD_BUFFER_SIZE);
357 prereadBufferSize_ = inFile_->gcount() + START_CODE_SIZE;
358 pPrereadBuffer_ = START_CODE_SIZE;
359 if (memcpy_s(prereadBuffer_.get(), START_CODE_SIZE, pBuffer - START_CODE_SIZE, START_CODE_SIZE) != EOK) {
360 return;
361 }
362 PtrStepExtraRead(bufferSize, &pBuffer);
363 } while (pPrereadBuffer_ != prereadBufferSize_);
364 mpegUnit_->resize(bufferSize);
365 }
366
ReadData(uint32_t index,OH_AVMemory * buffer)367 int32_t VDecFuzzSample::ReadData(uint32_t index, OH_AVMemory *buffer)
368 {
369 uint32_t bufferSize = 0;
370 if (inFile_->tellg() == 0) {
371 inFile_->read(reinterpret_cast<char *>(prereadBuffer_.get() + START_CODE_SIZE), PREREAD_BUFFER_SIZE);
372 prereadBufferSize_ = inFile_->gcount() + START_CODE_SIZE;
373 pPrereadBuffer_ = START_CODE_SIZE;
374 }
375
376 if (inFile_->eof() && finishLastPush) {
377 SetEOS(index);
378 mpegUnit_->resize(0);
379 return 1;
380 }
381
382 GetBufferSize();
383 bufferSize = mpegUnit_->size();
384 return SendData(bufferSize, index, buffer);
385 }
386
SendData(uint32_t bufferSize,uint32_t index,OH_AVMemory * buffer)387 uint32_t VDecFuzzSample::SendData(uint32_t bufferSize, uint32_t index, OH_AVMemory *buffer)
388 {
389 OH_AVCodecBufferAttr attr;
390 uint8_t *frameBuffer = nullptr;
391 if (bufferSize > 0) {
392 frameBuffer = new uint8_t[bufferSize];
393 } else {
394 delete[] frameBuffer;
395 return 0;
396 }
397 memcpy_s(frameBuffer, bufferSize, mpegUnit_->data(), bufferSize);
398 attr.pts = GetSystemTimeUs();
399 attr.size = bufferSize;
400 attr.offset = 0;
401 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
402
403 if (pPrereadBuffer_ == prereadBufferSize_ && inFile_->eof()) {
404 finishLastPush = true;
405 }
406 int32_t size = OH_AVMemory_GetSize(buffer);
407 if (size < attr.size) {
408 delete[] frameBuffer;
409 cout << "ERROR:AVMemory not enough, buffer size" << attr.size << " AVMemory Size " << size << endl;
410 isRunning_.store(false);
411 return 1;
412 }
413 uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
414 if (memcpy_s(bufferAddr, size, frameBuffer, attr.size) != EOK) {
415 delete[] frameBuffer;
416 cout << "Fatal: memcpy fail" << endl;
417 isRunning_.store(false);
418 return 1;
419 }
420 delete[] frameBuffer;
421
422 int ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
423 if (ret != AV_ERR_OK) {
424 errCount++;
425 cout << "push input data failed, error:" << ret << endl;
426 }
427
428 if (inFile_->eof() && finishLastPush && repeatRun) {
429 inFile_->clear();
430 inFile_->seekg(0, ios::beg);
431 finishLastPush = false;
432 cout << "repeat" << endl;
433 return 0;
434 }
435
436 frameCount_ = frameCount_ + 1;
437 return 0;
438 }
439
InputFuncAVCC()440 void VDecFuzzSample::InputFuncAVCC()
441 {
442 frameCount_ = 1;
443 errCount = 0;
444 while (true) {
445 if (!isRunning_.load()) {
446 break;
447 }
448 unique_lock<mutex> lock(signal_->inMutex_);
449 signal_->inCond_.wait(lock, [this]() {
450 if (!isRunning_.load()) {
451 cout << "quit signal" << endl;
452 return true;
453 }
454 return signal_->inIdxQueue_.size() > 0;
455 });
456 if (!isRunning_.load()) {
457 break;
458 }
459 uint32_t index = signal_->inIdxQueue_.front();
460 auto buffer = signal_->inBufferQueue_.front();
461 signal_->inIdxQueue_.pop();
462 signal_->inBufferQueue_.pop();
463 lock.unlock();
464 int ret = ReadData(index, buffer);
465 if (ret == 1) {
466 break;
467 }
468 }
469 }
470
InputFuncFUZZ(const uint8_t * data,size_t size)471 OH_AVErrCode VDecFuzzSample::InputFuncFUZZ(const uint8_t *data, size_t size)
472 {
473 if (!isRunning_.load())
474 return AV_ERR_TIMEOUT;
475 uint32_t index;
476 unique_lock<mutex> lock(signal_->inMutex_);
477 signal_->inCond_.wait(lock, [this]() {
478 if (!isRunning_.load()) {
479 return true;
480 }
481 return signal_->inIdxQueue_.size() > 0;
482 });
483 if (!isRunning_.load())
484 return AV_ERR_TIMEOUT;
485 index = signal_->inIdxQueue_.front();
486 auto buffer = signal_->inBufferQueue_.front();
487 signal_->inIdxQueue_.pop();
488 signal_->inBufferQueue_.pop();
489 lock.unlock();
490 int32_t bufferSize = OH_AVMemory_GetSize(buffer);
491 uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
492
493 if (memcpy_s(bufferAddr, bufferSize, data, size) != EOK) {
494 cout << "Fatal: memcpy fail" << endl;
495 return AV_ERR_NO_MEMORY;
496 }
497 OH_AVCodecBufferAttr attr;
498 attr.pts = GetSystemTimeUs();
499 attr.size = bufferSize;
500 attr.offset = 0;
501 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
502 OH_AVErrCode ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
503 return ret;
504 }
505
SetEOS(uint32_t index)506 void VDecFuzzSample::SetEOS(uint32_t index)
507 {
508 OH_AVCodecBufferAttr attr;
509 attr.pts = 0;
510 attr.size = 0;
511 attr.offset = 0;
512 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
513 int32_t res = OH_VideoDecoder_PushInputData(vdec_, index, attr);
514 cout << "OH_VideoDecoder_PushInputData EOS res: " << res << endl;
515 }
516
Flush()517 int32_t VDecFuzzSample::Flush()
518 {
519 unique_lock<mutex> inLock(signal_->inMutex_);
520 clearIntqueue(signal_->inIdxQueue_);
521 signal_->inCond_.notify_all();
522 inLock.unlock();
523 unique_lock<mutex> outLock(signal_->outMutex_);
524 clearIntqueue(signal_->outIdxQueue_);
525 clearBufferqueue(signal_->attrQueue_);
526 signal_->outCond_.notify_all();
527 isRunning_.store(false);
528 outLock.unlock();
529
530 return OH_VideoDecoder_Flush(vdec_);
531 }
532
Reset()533 int32_t VDecFuzzSample::Reset()
534 {
535 isRunning_.store(false);
536 StopInloop();
537 ReleaseInFile();
538 return OH_VideoDecoder_Reset(vdec_);
539 }
540
Release()541 int32_t VDecFuzzSample::Release()
542 {
543 int ret = 0;
544 if (vdec_ != nullptr) {
545 ret = OH_VideoDecoder_Destroy(vdec_);
546 vdec_ = nullptr;
547 }
548 if (signal_ != nullptr) {
549 clearAvBufferQueue(signal_->inBufferQueue_);
550 clearAvBufferQueue(signal_->outBufferQueue_);
551 delete signal_;
552 signal_ = nullptr;
553 }
554 return ret;
555 }
556
Stop()557 int32_t VDecFuzzSample::Stop()
558 {
559 StopInloop();
560 clearIntqueue(signal_->outIdxQueue_);
561 clearBufferqueue(signal_->attrQueue_);
562 ReleaseInFile();
563 return OH_VideoDecoder_Stop(vdec_);
564 }
565
Start()566 int32_t VDecFuzzSample::Start()
567 {
568 int32_t ret = 0;
569 ret = OH_VideoDecoder_Start(vdec_);
570 if (ret == AV_ERR_OK) {
571 isRunning_.store(true);
572 }
573 return ret;
574 }
575
SetParameter(OH_AVFormat * format)576 int32_t VDecFuzzSample::SetParameter(OH_AVFormat *format)
577 {
578 return OH_VideoDecoder_SetParameter(vdec_, format);
579 }