| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // The bulk of this file is support code; sorry about that. Here's an overview | 5 // The bulk of this file is support code; sorry about that. Here's an overview |
| 6 // to hopefully help readers of this code: | 6 // to hopefully help readers of this code: |
| 7 // - RenderingHelper is charged with interacting with X11/{EGL/GLES2,GLX/GL} or | 7 // - RenderingHelper is charged with interacting with X11/{EGL/GLES2,GLX/GL} or |
| 8 // Win/EGL. | 8 // Win/EGL. |
| 9 // - ClientState is an enum for the state of the decode client used by the test. | 9 // - ClientState is an enum for the state of the decode client used by the test. |
| 10 // - ClientStateNotification is a barrier abstraction that allows the test code | 10 // - ClientStateNotification is a barrier abstraction that allows the test code |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 double fps, | 209 double fps, |
| 210 ReusePictureCB reuse_picture_cb); | 210 ReusePictureCB reuse_picture_cb); |
| 211 virtual ~ThrottlingVDAClient(); | 211 virtual ~ThrottlingVDAClient(); |
| 212 | 212 |
| 213 // VideoDecodeAccelerator::Client implementation | 213 // VideoDecodeAccelerator::Client implementation |
| 214 virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers, | 214 virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers, |
| 215 const gfx::Size& dimensions, | 215 const gfx::Size& dimensions, |
| 216 uint32 texture_target) OVERRIDE; | 216 uint32 texture_target) OVERRIDE; |
| 217 virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; | 217 virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; |
| 218 virtual void PictureReady(const media::Picture& picture) OVERRIDE; | 218 virtual void PictureReady(const media::Picture& picture) OVERRIDE; |
| 219 virtual void NotifyInitializeDone() OVERRIDE; | |
| 220 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; | 219 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; |
| 221 virtual void NotifyFlushDone() OVERRIDE; | 220 virtual void NotifyFlushDone() OVERRIDE; |
| 222 virtual void NotifyResetDone() OVERRIDE; | 221 virtual void NotifyResetDone() OVERRIDE; |
| 223 virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; | 222 virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; |
| 224 | 223 |
| 225 int num_decoded_frames() { return num_decoded_frames_; } | 224 int num_decoded_frames() { return num_decoded_frames_; } |
| 226 | 225 |
| 227 private: | 226 private: |
| 228 | 227 |
| 229 void CallClientPictureReady(int version); | 228 void CallClientPictureReady(int version); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 if (!pending_pictures_.empty()) { | 304 if (!pending_pictures_.empty()) { |
| 306 base::MessageLoop::current()->PostDelayedTask( | 305 base::MessageLoop::current()->PostDelayedTask( |
| 307 FROM_HERE, | 306 FROM_HERE, |
| 308 base::Bind(&ThrottlingVDAClient::CallClientPictureReady, | 307 base::Bind(&ThrottlingVDAClient::CallClientPictureReady, |
| 309 AsWeakPtr(), | 308 AsWeakPtr(), |
| 310 stream_version_), | 309 stream_version_), |
| 311 next_frame_delivered_time_ - base::TimeTicks::Now()); | 310 next_frame_delivered_time_ - base::TimeTicks::Now()); |
| 312 } | 311 } |
| 313 } | 312 } |
| 314 | 313 |
| 315 void ThrottlingVDAClient::NotifyInitializeDone() { | |
| 316 client_->NotifyInitializeDone(); | |
| 317 } | |
| 318 | |
| 319 void ThrottlingVDAClient::NotifyEndOfBitstreamBuffer( | 314 void ThrottlingVDAClient::NotifyEndOfBitstreamBuffer( |
| 320 int32 bitstream_buffer_id) { | 315 int32 bitstream_buffer_id) { |
| 321 client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id); | 316 client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id); |
| 322 } | 317 } |
| 323 | 318 |
| 324 void ThrottlingVDAClient::NotifyFlushDone() { | 319 void ThrottlingVDAClient::NotifyFlushDone() { |
| 325 if (!pending_pictures_.empty()) { | 320 if (!pending_pictures_.empty()) { |
| 326 base::MessageLoop::current()->PostDelayedTask( | 321 base::MessageLoop::current()->PostDelayedTask( |
| 327 FROM_HERE, | 322 FROM_HERE, |
| 328 base::Bind(&ThrottlingVDAClient::NotifyFlushDone, | 323 base::Bind(&ThrottlingVDAClient::NotifyFlushDone, |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 void CreateAndStartDecoder(); | 385 void CreateAndStartDecoder(); |
| 391 | 386 |
| 392 // VideoDecodeAccelerator::Client implementation. | 387 // VideoDecodeAccelerator::Client implementation. |
| 393 // The heart of the Client. | 388 // The heart of the Client. |
| 394 virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers, | 389 virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers, |
| 395 const gfx::Size& dimensions, | 390 const gfx::Size& dimensions, |
| 396 uint32 texture_target) OVERRIDE; | 391 uint32 texture_target) OVERRIDE; |
| 397 virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; | 392 virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; |
| 398 virtual void PictureReady(const media::Picture& picture) OVERRIDE; | 393 virtual void PictureReady(const media::Picture& picture) OVERRIDE; |
| 399 // Simple state changes. | 394 // Simple state changes. |
| 400 virtual void NotifyInitializeDone() OVERRIDE; | |
| 401 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; | 395 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; |
| 402 virtual void NotifyFlushDone() OVERRIDE; | 396 virtual void NotifyFlushDone() OVERRIDE; |
| 403 virtual void NotifyResetDone() OVERRIDE; | 397 virtual void NotifyResetDone() OVERRIDE; |
| 404 virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; | 398 virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; |
| 405 | 399 |
| 406 void OutputFrameDeliveryTimes(base::File* output); | 400 void OutputFrameDeliveryTimes(base::File* output); |
| 407 | 401 |
| 408 void NotifyFrameDropped(int32 picture_buffer_id); | 402 void NotifyFrameDropped(int32 picture_buffer_id); |
| 409 | 403 |
| 410 // Simple getters for inspecting the state of the Client. | 404 // Simple getters for inspecting the state of the Client. |
| 411 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; } | 405 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; } |
| 412 int num_skipped_fragments() { return num_skipped_fragments_; } | 406 int num_skipped_fragments() { return num_skipped_fragments_; } |
| 413 int num_queued_fragments() { return num_queued_fragments_; } | 407 int num_queued_fragments() { return num_queued_fragments_; } |
| 414 int num_decoded_frames(); | 408 int num_decoded_frames(); |
| 415 double frames_per_second(); | 409 double frames_per_second(); |
| 416 // Return the median of the decode time in milliseconds. | 410 // Return the median of the decode time in milliseconds. |
| 417 int decode_time_median(); | 411 int decode_time_median(); |
| 418 bool decoder_deleted() { return !decoder_.get(); } | 412 bool decoder_deleted() { return !decoder_.get(); } |
| 419 | 413 |
| 420 private: | 414 private: |
| 421 typedef std::map<int, media::PictureBuffer*> PictureBufferById; | 415 typedef std::map<int, media::PictureBuffer*> PictureBufferById; |
| 422 | 416 |
| 423 void SetState(ClientState new_state); | 417 void SetState(ClientState new_state); |
| 418 void FinishInitialization(); |
| 424 | 419 |
| 425 // Delete the associated decoder helper. | 420 // Delete the associated decoder helper. |
| 426 void DeleteDecoder(); | 421 void DeleteDecoder(); |
| 427 | 422 |
| 428 // Compute & return the first encoded bytes (including a start frame) to send | 423 // Compute & return the first encoded bytes (including a start frame) to send |
| 429 // to the decoder, starting at |start_pos| and returning one fragment. Skips | 424 // to the decoder, starting at |start_pos| and returning one fragment. Skips |
| 430 // to the first decodable position. | 425 // to the first decodable position. |
| 431 std::string GetBytesForFirstFragment(size_t start_pos, size_t* end_pos); | 426 std::string GetBytesForFirstFragment(size_t start_pos, size_t* end_pos); |
| 432 // Compute & return the encoded bytes of next fragment to send to the decoder | 427 // Compute & return the encoded bytes of next fragment to send to the decoder |
| 433 // (based on |start_pos|). | 428 // (based on |start_pos|). |
| 434 std::string GetBytesForNextFragment(size_t start_pos, size_t* end_pos); | 429 std::string GetBytesForNextFragment(size_t start_pos, size_t* end_pos); |
| 435 // Helpers for GetBytesForNextFragment above. | 430 // Helpers for GetBytesForNextFragment above. |
| 436 void GetBytesForNextNALU(size_t start_pos, size_t* end_pos); // For h.264. | 431 void GetBytesForNextNALU(size_t start_pos, size_t* end_pos); // For h.264. |
| 437 std::string GetBytesForNextFrame( | 432 std::string GetBytesForNextFrame( |
| 438 size_t start_pos, size_t* end_pos); // For VP8. | 433 size_t start_pos, size_t* end_pos); // For VP8. |
| 439 | 434 |
| 440 // Request decode of the next fragment in the encoded data. | 435 // Request decode of the next fragment in the encoded data. |
| 441 void DecodeNextFragment(); | 436 void DecodeNextFragment(); |
| 442 | 437 |
| 443 RenderingHelper* rendering_helper_; | 438 RenderingHelper* rendering_helper_; |
| 444 int rendering_window_id_; | 439 int rendering_window_id_; |
| 445 std::string encoded_data_; | 440 std::string encoded_data_; |
| 446 const int num_in_flight_decodes_; | 441 const int num_in_flight_decodes_; |
| 447 int outstanding_decodes_; | 442 int outstanding_decodes_; |
| 448 size_t encoded_data_next_pos_to_decode_; | 443 size_t encoded_data_next_pos_to_decode_; |
| 449 int next_bitstream_buffer_id_; | 444 int next_bitstream_buffer_id_; |
| 450 ClientStateNotification<ClientState>* note_; | 445 ClientStateNotification<ClientState>* note_; |
| 451 scoped_ptr<VideoDecodeAccelerator> decoder_; | 446 scoped_ptr<VideoDecodeAccelerator> decoder_; |
| 447 scoped_ptr<base::WeakPtrFactory<VideoDecodeAccelerator> > |
| 448 weak_decoder_factory_; |
| 452 std::set<int> outstanding_texture_ids_; | 449 std::set<int> outstanding_texture_ids_; |
| 453 int remaining_play_throughs_; | 450 int remaining_play_throughs_; |
| 454 int reset_after_frame_num_; | 451 int reset_after_frame_num_; |
| 455 int delete_decoder_state_; | 452 int delete_decoder_state_; |
| 456 ClientState state_; | 453 ClientState state_; |
| 457 int num_skipped_fragments_; | 454 int num_skipped_fragments_; |
| 458 int num_queued_fragments_; | 455 int num_queued_fragments_; |
| 459 int num_decoded_frames_; | 456 int num_decoded_frames_; |
| 460 int num_done_bitstream_buffers_; | 457 int num_done_bitstream_buffers_; |
| 461 PictureBufferById picture_buffers_by_id_; | 458 PictureBufferById picture_buffers_by_id_; |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 569 device.Pass(), | 566 device.Pass(), |
| 570 base::MessageLoopProxy::current())); | 567 base::MessageLoopProxy::current())); |
| 571 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) | 568 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) |
| 572 CHECK_EQ(gfx::kGLImplementationDesktopGL, gfx::GetGLImplementation()) | 569 CHECK_EQ(gfx::kGLImplementationDesktopGL, gfx::GetGLImplementation()) |
| 573 << "Hardware video decode does not work with OSMesa"; | 570 << "Hardware video decode does not work with OSMesa"; |
| 574 decoder_.reset(new VaapiVideoDecodeAccelerator( | 571 decoder_.reset(new VaapiVideoDecodeAccelerator( |
| 575 static_cast<Display*>(rendering_helper_->GetGLDisplay()), | 572 static_cast<Display*>(rendering_helper_->GetGLDisplay()), |
| 576 base::Bind(&DoNothingReturnTrue))); | 573 base::Bind(&DoNothingReturnTrue))); |
| 577 #endif // OS_WIN | 574 #endif // OS_WIN |
| 578 CHECK(decoder_.get()); | 575 CHECK(decoder_.get()); |
| 576 weak_decoder_factory_.reset( |
| 577 new base::WeakPtrFactory<VideoDecodeAccelerator>(decoder_.get())); |
| 579 SetState(CS_DECODER_SET); | 578 SetState(CS_DECODER_SET); |
| 580 if (decoder_deleted()) | 579 if (decoder_deleted()) |
| 581 return; | 580 return; |
| 582 | 581 |
| 583 CHECK(decoder_->Initialize(profile_, client)); | 582 CHECK(decoder_->Initialize(profile_, client)); |
| 583 FinishInitialization(); |
| 584 } | 584 } |
| 585 | 585 |
| 586 void GLRenderingVDAClient::ProvidePictureBuffers( | 586 void GLRenderingVDAClient::ProvidePictureBuffers( |
| 587 uint32 requested_num_of_buffers, | 587 uint32 requested_num_of_buffers, |
| 588 const gfx::Size& dimensions, | 588 const gfx::Size& dimensions, |
| 589 uint32 texture_target) { | 589 uint32 texture_target) { |
| 590 if (decoder_deleted()) | 590 if (decoder_deleted()) |
| 591 return; | 591 return; |
| 592 std::vector<media::PictureBuffer> buffers; | 592 std::vector<media::PictureBuffer> buffers; |
| 593 | 593 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 CHECK(picture_buffer); | 653 CHECK(picture_buffer); |
| 654 if (!suppress_rendering_) { | 654 if (!suppress_rendering_) { |
| 655 rendering_helper_->RenderTexture(texture_target_, | 655 rendering_helper_->RenderTexture(texture_target_, |
| 656 picture_buffer->texture_id()); | 656 picture_buffer->texture_id()); |
| 657 } | 657 } |
| 658 | 658 |
| 659 if (num_decoded_frames() > delay_reuse_after_frame_num_) { | 659 if (num_decoded_frames() > delay_reuse_after_frame_num_) { |
| 660 base::MessageLoop::current()->PostDelayedTask( | 660 base::MessageLoop::current()->PostDelayedTask( |
| 661 FROM_HERE, | 661 FROM_HERE, |
| 662 base::Bind(&VideoDecodeAccelerator::ReusePictureBuffer, | 662 base::Bind(&VideoDecodeAccelerator::ReusePictureBuffer, |
| 663 decoder_->AsWeakPtr(), | 663 weak_decoder_factory_->GetWeakPtr(), |
| 664 picture.picture_buffer_id()), | 664 picture.picture_buffer_id()), |
| 665 kReuseDelay); | 665 kReuseDelay); |
| 666 } else { | 666 } else { |
| 667 decoder_->ReusePictureBuffer(picture.picture_buffer_id()); | 667 decoder_->ReusePictureBuffer(picture.picture_buffer_id()); |
| 668 } | 668 } |
| 669 } | 669 } |
| 670 | 670 |
| 671 void GLRenderingVDAClient::NotifyInitializeDone() { | |
| 672 SetState(CS_INITIALIZED); | |
| 673 initialize_done_ticks_ = base::TimeTicks::Now(); | |
| 674 | |
| 675 if (reset_after_frame_num_ == START_OF_STREAM_RESET) { | |
| 676 reset_after_frame_num_ = MID_STREAM_RESET; | |
| 677 decoder_->Reset(); | |
| 678 return; | |
| 679 } | |
| 680 | |
| 681 for (int i = 0; i < num_in_flight_decodes_; ++i) | |
| 682 DecodeNextFragment(); | |
| 683 DCHECK_EQ(outstanding_decodes_, num_in_flight_decodes_); | |
| 684 } | |
| 685 | |
| 686 void GLRenderingVDAClient::NotifyEndOfBitstreamBuffer( | 671 void GLRenderingVDAClient::NotifyEndOfBitstreamBuffer( |
| 687 int32 bitstream_buffer_id) { | 672 int32 bitstream_buffer_id) { |
| 688 // TODO(fischman): this test currently relies on this notification to make | 673 // TODO(fischman): this test currently relies on this notification to make |
| 689 // forward progress during a Reset(). But the VDA::Reset() API doesn't | 674 // forward progress during a Reset(). But the VDA::Reset() API doesn't |
| 690 // guarantee this, so stop relying on it (and remove the notifications from | 675 // guarantee this, so stop relying on it (and remove the notifications from |
| 691 // VaapiVideoDecodeAccelerator::FinishReset()). | 676 // VaapiVideoDecodeAccelerator::FinishReset()). |
| 692 ++num_done_bitstream_buffers_; | 677 ++num_done_bitstream_buffers_; |
| 693 --outstanding_decodes_; | 678 --outstanding_decodes_; |
| 694 if (decode_calls_per_second_ == 0) | 679 if (decode_calls_per_second_ == 0) |
| 695 DecodeNextFragment(); | 680 DecodeNextFragment(); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 717 return; | 702 return; |
| 718 } else if (reset_after_frame_num_ == START_OF_STREAM_RESET) { | 703 } else if (reset_after_frame_num_ == START_OF_STREAM_RESET) { |
| 719 reset_after_frame_num_ = END_OF_STREAM_RESET; | 704 reset_after_frame_num_ = END_OF_STREAM_RESET; |
| 720 for (int i = 0; i < num_in_flight_decodes_; ++i) | 705 for (int i = 0; i < num_in_flight_decodes_; ++i) |
| 721 DecodeNextFragment(); | 706 DecodeNextFragment(); |
| 722 return; | 707 return; |
| 723 } | 708 } |
| 724 | 709 |
| 725 if (remaining_play_throughs_) { | 710 if (remaining_play_throughs_) { |
| 726 encoded_data_next_pos_to_decode_ = 0; | 711 encoded_data_next_pos_to_decode_ = 0; |
| 727 NotifyInitializeDone(); | 712 FinishInitialization(); |
| 728 return; | 713 return; |
| 729 } | 714 } |
| 730 | 715 |
| 731 SetState(CS_RESET); | 716 SetState(CS_RESET); |
| 732 if (!decoder_deleted()) | 717 if (!decoder_deleted()) |
| 733 DeleteDecoder(); | 718 DeleteDecoder(); |
| 734 } | 719 } |
| 735 | 720 |
| 736 void GLRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) { | 721 void GLRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) { |
| 737 SetState(CS_ERROR); | 722 SetState(CS_ERROR); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 762 | 747 |
| 763 void GLRenderingVDAClient::SetState(ClientState new_state) { | 748 void GLRenderingVDAClient::SetState(ClientState new_state) { |
| 764 note_->Notify(new_state); | 749 note_->Notify(new_state); |
| 765 state_ = new_state; | 750 state_ = new_state; |
| 766 if (!remaining_play_throughs_ && new_state == delete_decoder_state_) { | 751 if (!remaining_play_throughs_ && new_state == delete_decoder_state_) { |
| 767 CHECK(!decoder_deleted()); | 752 CHECK(!decoder_deleted()); |
| 768 DeleteDecoder(); | 753 DeleteDecoder(); |
| 769 } | 754 } |
| 770 } | 755 } |
| 771 | 756 |
| 757 void GLRenderingVDAClient::FinishInitialization() { |
| 758 SetState(CS_INITIALIZED); |
| 759 initialize_done_ticks_ = base::TimeTicks::Now(); |
| 760 |
| 761 if (reset_after_frame_num_ == START_OF_STREAM_RESET) { |
| 762 reset_after_frame_num_ = MID_STREAM_RESET; |
| 763 decoder_->Reset(); |
| 764 return; |
| 765 } |
| 766 |
| 767 for (int i = 0; i < num_in_flight_decodes_; ++i) |
| 768 DecodeNextFragment(); |
| 769 DCHECK_EQ(outstanding_decodes_, num_in_flight_decodes_); |
| 770 } |
| 771 |
| 772 void GLRenderingVDAClient::DeleteDecoder() { | 772 void GLRenderingVDAClient::DeleteDecoder() { |
| 773 if (decoder_deleted()) | 773 if (decoder_deleted()) |
| 774 return; | 774 return; |
| 775 weak_decoder_factory_.reset(); |
| 775 decoder_.release()->Destroy(); | 776 decoder_.release()->Destroy(); |
| 776 STLClearObject(&encoded_data_); | 777 STLClearObject(&encoded_data_); |
| 777 for (std::set<int>::iterator it = outstanding_texture_ids_.begin(); | 778 for (std::set<int>::iterator it = outstanding_texture_ids_.begin(); |
| 778 it != outstanding_texture_ids_.end(); ++it) { | 779 it != outstanding_texture_ids_.end(); ++it) { |
| 779 rendering_helper_->DeleteTexture(*it); | 780 rendering_helper_->DeleteTexture(*it); |
| 780 } | 781 } |
| 781 outstanding_texture_ids_.clear(); | 782 outstanding_texture_ids_.clear(); |
| 782 // Cascade through the rest of the states to simplify test code below. | 783 // Cascade through the rest of the states to simplify test code below. |
| 783 for (int i = state_ + 1; i < CS_MAX; ++i) | 784 for (int i = state_ + 1; i < CS_MAX; ++i) |
| 784 SetState(static_cast<ClientState>(i)); | 785 SetState(static_cast<ClientState>(i)); |
| (...skipping 784 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1569 } | 1570 } |
| 1570 if (it->first == "v" || it->first == "vmodule") | 1571 if (it->first == "v" || it->first == "vmodule") |
| 1571 continue; | 1572 continue; |
| 1572 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; | 1573 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; |
| 1573 } | 1574 } |
| 1574 | 1575 |
| 1575 base::ShadowingAtExitManager at_exit_manager; | 1576 base::ShadowingAtExitManager at_exit_manager; |
| 1576 | 1577 |
| 1577 return RUN_ALL_TESTS(); | 1578 return RUN_ALL_TESTS(); |
| 1578 } | 1579 } |
| OLD | NEW |