source: 3DVCSoftware/branches/HTM-15.1-dev0-Disney/source/Lib/TLibCommon/TComPicSym.cpp @ 1341

Last change on this file since 1341 was 1313, checked in by tech, 9 years ago

Merged 14.1-update-dev1@1312.

  • Property svn:eol-style set to native
File size: 17.5 KB
Line 
1/* The copyright in this software is being made available under the BSD
2 * License, included below. This software may be subject to other third party
3 * and contributor rights, including patent rights, and no such rights are
4 * granted under this license.
5 *
6 * Copyright (c) 2010-2015, ITU/ISO/IEC
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 *  * Redistributions of source code must retain the above copyright notice,
13 *    this list of conditions and the following disclaimer.
14 *  * Redistributions in binary form must reproduce the above copyright notice,
15 *    this list of conditions and the following disclaimer in the documentation
16 *    and/or other materials provided with the distribution.
17 *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
18 *    be used to endorse or promote products derived from this software without
19 *    specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/** \file     TComPicSym.cpp
35    \brief    picture symbol class
36*/
37
38#include "TComPicSym.h"
39#include "TComSampleAdaptiveOffset.h"
40#include "TComSlice.h"
41
42//! \ingroup TLibCommon
43//! \{
44
45// ====================================================================================================================
46// Constructor / destructor / create / destroy
47// ====================================================================================================================
48
49TComPicSym::TComPicSym()
50:m_frameWidthInCtus(0)
51,m_frameHeightInCtus(0)
52,m_uiMinCUWidth(0)
53,m_uiMinCUHeight(0)
54,m_uhTotalDepth(0)
55,m_numPartitionsInCtu(0)
56,m_numPartInCtuWidth(0)
57,m_numPartInCtuHeight(0)
58,m_numCtusInFrame(0)
59,m_apSlices()
60,m_pictureCtuArray(NULL)
61,m_numTileColumnsMinus1(0)
62,m_numTileRowsMinus1(0)
63,m_ctuTsToRsAddrMap(NULL)
64,m_puiTileIdxMap(NULL)
65,m_ctuRsToTsAddrMap(NULL)
66,m_saoBlkParams(NULL)
67#if ADAPTIVE_QP_SELECTION
68,m_pParentARLBuffer(NULL)
69#endif
70{}
71
72
73Void TComPicSym::create  ( const TComSPS &sps, const TComPPS &pps, UInt uiMaxDepth )
74{
75  UInt i;
76  m_sps = sps;
77  m_pps = pps;
78
79  const ChromaFormat chromaFormatIDC = sps.getChromaFormatIdc();
80  const Int iPicWidth      = sps.getPicWidthInLumaSamples();
81  const Int iPicHeight     = sps.getPicHeightInLumaSamples();
82  const UInt uiMaxCuWidth  = sps.getMaxCUWidth();
83  const UInt uiMaxCuHeight = sps.getMaxCUHeight();
84
85  m_uhTotalDepth       = uiMaxDepth;
86  m_numPartitionsInCtu = 1<<(m_uhTotalDepth<<1);
87
88  m_uiMinCUWidth       = uiMaxCuWidth  >> m_uhTotalDepth;
89  m_uiMinCUHeight      = uiMaxCuHeight >> m_uhTotalDepth;
90
91  m_numPartInCtuWidth  = uiMaxCuWidth  / m_uiMinCUWidth;  // equivalent to 1<<m_uhTotalDepth
92  m_numPartInCtuHeight = uiMaxCuHeight / m_uiMinCUHeight; // equivalent to 1<<m_uhTotalDepth
93
94  m_frameWidthInCtus   = ( iPicWidth %uiMaxCuWidth  ) ? iPicWidth /uiMaxCuWidth  + 1 : iPicWidth /uiMaxCuWidth;
95  m_frameHeightInCtus  = ( iPicHeight%uiMaxCuHeight ) ? iPicHeight/uiMaxCuHeight + 1 : iPicHeight/uiMaxCuHeight;
96
97  m_numCtusInFrame     = m_frameWidthInCtus * m_frameHeightInCtus;
98  m_pictureCtuArray    = new TComDataCU*[m_numCtusInFrame];
99
100  clearSliceBuffer();
101  allocateNewSlice();
102
103#if ADAPTIVE_QP_SELECTION
104  if (m_pParentARLBuffer == NULL)
105  {
106     m_pParentARLBuffer = new TCoeff[uiMaxCuWidth*uiMaxCuHeight*MAX_NUM_COMPONENT];
107  }
108#endif
109
110  for ( i=0; i<m_numCtusInFrame ; i++ )
111  {
112    m_pictureCtuArray[i] = new TComDataCU;
113    m_pictureCtuArray[i]->create( chromaFormatIDC, m_numPartitionsInCtu, uiMaxCuWidth, uiMaxCuHeight, false, uiMaxCuWidth >> m_uhTotalDepth
114#if ADAPTIVE_QP_SELECTION
115      , m_pParentARLBuffer
116#endif
117      );
118  }
119
120  m_ctuTsToRsAddrMap = new UInt[m_numCtusInFrame+1];
121  m_puiTileIdxMap    = new UInt[m_numCtusInFrame];
122  m_ctuRsToTsAddrMap = new UInt[m_numCtusInFrame+1];
123
124  for( i=0; i<m_numCtusInFrame; i++ )
125  {
126    m_ctuTsToRsAddrMap[i] = i;
127    m_ctuRsToTsAddrMap[i] = i;
128  }
129
130  m_saoBlkParams = new SAOBlkParam[m_numCtusInFrame];
131
132
133  xInitTiles();
134  xInitCtuTsRsAddrMaps();
135
136}
137
138Void TComPicSym::destroy()
139{
140  clearSliceBuffer();
141
142  for (Int i = 0; i < m_numCtusInFrame; i++)
143  {
144    m_pictureCtuArray[i]->destroy();
145    delete m_pictureCtuArray[i];
146    m_pictureCtuArray[i] = NULL;
147  }
148  delete [] m_pictureCtuArray;
149  m_pictureCtuArray = NULL;
150
151  delete [] m_ctuTsToRsAddrMap;
152  m_ctuTsToRsAddrMap = NULL;
153
154  delete [] m_puiTileIdxMap;
155  m_puiTileIdxMap = NULL;
156
157  delete [] m_ctuRsToTsAddrMap;
158  m_ctuRsToTsAddrMap = NULL;
159
160  if(m_saoBlkParams)
161  {
162    delete[] m_saoBlkParams; m_saoBlkParams = NULL;
163  }
164
165#if ADAPTIVE_QP_SELECTION
166  delete [] m_pParentARLBuffer;
167  m_pParentARLBuffer = NULL;
168#endif
169}
170
171Void TComPicSym::allocateNewSlice()
172{
173  m_apSlices.push_back(new TComSlice);
174  m_apSlices.back()->setPPS(&m_pps);
175  m_apSlices.back()->setSPS(&m_sps);
176  if (m_apSlices.size()>=2)
177  {
178    m_apSlices.back()->copySliceInfo( m_apSlices[m_apSlices.size()-2] );
179    m_apSlices.back()->initSlice();
180  }
181}
182
183Void TComPicSym::clearSliceBuffer()
184{
185  for (UInt i = 0; i < UInt(m_apSlices.size()); i++)
186  {
187    delete m_apSlices[i];
188  }
189  m_apSlices.clear();
190}
191
192Void TComPicSym::xInitCtuTsRsAddrMaps()
193{
194  //generate the Coding Order Map and Inverse Coding Order Map
195  for(Int ctuTsAddr=0, ctuRsAddr=0; ctuTsAddr<getNumberOfCtusInFrame(); ctuTsAddr++, ctuRsAddr = xCalculateNextCtuRSAddr(ctuRsAddr))
196  {
197    setCtuTsToRsAddrMap(ctuTsAddr, ctuRsAddr);
198    setCtuRsToTsAddrMap(ctuRsAddr, ctuTsAddr);
199  }
200  setCtuTsToRsAddrMap(getNumberOfCtusInFrame(), getNumberOfCtusInFrame());
201  setCtuRsToTsAddrMap(getNumberOfCtusInFrame(), getNumberOfCtusInFrame());
202}
203
204Void TComPicSym::xInitTiles()
205{
206  //set NumColumnsMinus1 and NumRowsMinus1
207  setNumTileColumnsMinus1( m_pps.getNumTileColumnsMinus1() );
208  setNumTileRowsMinus1(    m_pps.getNumTileRowsMinus1()    );
209
210  const Int numCols = m_pps.getNumTileColumnsMinus1() + 1;
211  const Int numRows = m_pps.getNumTileRowsMinus1() + 1;
212  const Int numTiles = numRows * numCols;
213
214  // allocate memory for tile parameters
215  m_tileParameters.resize(numTiles);
216
217  if( m_pps.getTileUniformSpacingFlag() )
218  {
219    //set width and height for each (uniform) tile
220    for(Int row=0; row < numRows; row++)
221    {
222      for(Int col=0; col < numCols; col++)
223      {
224        const Int tileIdx = row * numCols + col;
225        m_tileParameters[tileIdx].setTileWidthInCtus(  (col+1)*getFrameWidthInCtus( )/numCols - (col*getFrameWidthInCtus( ))/numCols );
226        m_tileParameters[tileIdx].setTileHeightInCtus( (row+1)*getFrameHeightInCtus()/numRows - (row*getFrameHeightInCtus())/numRows );
227      }
228    }
229  }
230  else
231  {
232    //set the width for each tile
233    for(Int row=0; row < numRows; row++)
234    {
235      Int cumulativeTileWidth = 0;
236      for(Int col=0; col < getNumTileColumnsMinus1(); col++)
237      {
238        m_tileParameters[row * numCols + col].setTileWidthInCtus( m_pps.getTileColumnWidth(col) );
239        cumulativeTileWidth += m_pps.getTileColumnWidth(col);
240      }
241      m_tileParameters[row * numCols + getNumTileColumnsMinus1()].setTileWidthInCtus( getFrameWidthInCtus()-cumulativeTileWidth );
242    }
243
244    //set the height for each tile
245    for(Int col=0; col < numCols; col++)
246    {
247      Int cumulativeTileHeight = 0;
248      for(Int row=0; row < getNumTileRowsMinus1(); row++)
249      {
250        m_tileParameters[row * numCols + col].setTileHeightInCtus( m_pps.getTileRowHeight(row) );
251        cumulativeTileHeight += m_pps.getTileRowHeight(row);
252      }
253      m_tileParameters[getNumTileRowsMinus1() * numCols + col].setTileHeightInCtus( getFrameHeightInCtus()-cumulativeTileHeight );
254    }
255  }
256
257  // Tile size check
258  Int minWidth  = 1;
259  Int minHeight = 1;
260  const Int profileIdc = m_sps.getPTL()->getGeneralPTL()->getProfileIdc();
261  if (  profileIdc == Profile::MAIN || profileIdc == Profile::MAIN10) //TODO: add more profiles to the tile-size check...
262  {
263    if (m_pps.getTilesEnabledFlag())
264    {
265      minHeight = 64  / m_sps.getMaxCUHeight();
266      minWidth  = 256 / m_sps.getMaxCUWidth();
267    }
268  }
269  for(Int row=0; row < numRows; row++)
270  {
271    for(Int col=0; col < numCols; col++)
272    {
273      const Int tileIdx = row * numCols + col;
274      assert (m_tileParameters[tileIdx].getTileWidthInCtus() >= minWidth);
275      assert (m_tileParameters[tileIdx].getTileHeightInCtus() >= minHeight);
276    }
277  }
278
279  //initialize each tile of the current picture
280  for( Int row=0; row < numRows; row++ )
281  {
282    for( Int col=0; col < numCols; col++ )
283    {
284      const Int tileIdx = row * numCols + col;
285
286      //initialize the RightEdgePosInCU for each tile
287      Int rightEdgePosInCTU = 0;
288      for( Int i=0; i <= col; i++ )
289      {
290        rightEdgePosInCTU += m_tileParameters[row * numCols + i].getTileWidthInCtus();
291      }
292      m_tileParameters[tileIdx].setRightEdgePosInCtus(rightEdgePosInCTU-1);
293
294      //initialize the BottomEdgePosInCU for each tile
295      Int bottomEdgePosInCTU = 0;
296      for( Int i=0; i <= row; i++ )
297      {
298        bottomEdgePosInCTU += m_tileParameters[i * numCols + col].getTileHeightInCtus();
299      }
300      m_tileParameters[tileIdx].setBottomEdgePosInCtus(bottomEdgePosInCTU-1);
301
302      //initialize the FirstCUAddr for each tile
303      m_tileParameters[tileIdx].setFirstCtuRsAddr( (m_tileParameters[tileIdx].getBottomEdgePosInCtus() - m_tileParameters[tileIdx].getTileHeightInCtus() + 1) * getFrameWidthInCtus() +
304                                                    m_tileParameters[tileIdx].getRightEdgePosInCtus()  - m_tileParameters[tileIdx].getTileWidthInCtus()  + 1);
305    }
306  }
307
308  Int  columnIdx = 0;
309  Int  rowIdx = 0;
310
311  //initialize the TileIdxMap
312  for( Int i=0; i<m_numCtusInFrame; i++)
313  {
314    for( Int col=0; col < numCols; col++)
315    {
316      if(i % getFrameWidthInCtus() <= m_tileParameters[col].getRightEdgePosInCtus())
317      {
318        columnIdx = col;
319        break;
320      }
321    }
322    for(Int row=0; row < numRows; row++)
323    {
324      if(i / getFrameWidthInCtus() <= m_tileParameters[row*numCols].getBottomEdgePosInCtus())
325      {
326        rowIdx = row;
327        break;
328      }
329    }
330    m_puiTileIdxMap[i] = rowIdx * numCols + columnIdx;
331  }
332}
333UInt TComPicSym::xCalculateNextCtuRSAddr( UInt currCtuRsAddr )
334{
335  UInt  nextCtuRsAddr;
336
337  //get the tile index for the current CTU
338  const UInt uiTileIdx = getTileIdxMap(currCtuRsAddr);
339
340  //get the raster scan address for the next CTU
341  if( currCtuRsAddr % m_frameWidthInCtus == getTComTile(uiTileIdx)->getRightEdgePosInCtus() && currCtuRsAddr / m_frameWidthInCtus == getTComTile(uiTileIdx)->getBottomEdgePosInCtus() )
342  //the current CTU is the last CTU of the tile
343  {
344    if(uiTileIdx+1 == getNumTiles())
345    {
346      nextCtuRsAddr = m_numCtusInFrame;
347    }
348    else
349    {
350      nextCtuRsAddr = getTComTile(uiTileIdx+1)->getFirstCtuRsAddr();
351    }
352  }
353  else //the current CTU is not the last CTU of the tile
354  {
355    if( currCtuRsAddr % m_frameWidthInCtus == getTComTile(uiTileIdx)->getRightEdgePosInCtus() )  //the current CTU is on the rightmost edge of the tile
356    {
357      nextCtuRsAddr = currCtuRsAddr + m_frameWidthInCtus - getTComTile(uiTileIdx)->getTileWidthInCtus() + 1;
358    }
359    else
360    {
361      nextCtuRsAddr = currCtuRsAddr + 1;
362    }
363  }
364
365  return nextCtuRsAddr;
366}
367
368Void TComPicSym::deriveLoopFilterBoundaryAvailibility(Int ctuRsAddr,
369                                                      Bool& isLeftAvail,
370                                                      Bool& isRightAvail,
371                                                      Bool& isAboveAvail,
372                                                      Bool& isBelowAvail,
373                                                      Bool& isAboveLeftAvail,
374                                                      Bool& isAboveRightAvail,
375                                                      Bool& isBelowLeftAvail,
376                                                      Bool& isBelowRightAvail
377                                                      )
378{
379
380  isLeftAvail      = (ctuRsAddr % m_frameWidthInCtus != 0);
381  isRightAvail     = (ctuRsAddr % m_frameWidthInCtus != m_frameWidthInCtus-1);
382  isAboveAvail     = (ctuRsAddr >= m_frameWidthInCtus );
383  isBelowAvail     = (ctuRsAddr <  m_numCtusInFrame - m_frameWidthInCtus);
384  isAboveLeftAvail = (isAboveAvail && isLeftAvail);
385  isAboveRightAvail= (isAboveAvail && isRightAvail);
386  isBelowLeftAvail = (isBelowAvail && isLeftAvail);
387  isBelowRightAvail= (isBelowAvail && isRightAvail);
388
389  Bool isLoopFiltAcrossTilePPS = getCtu(ctuRsAddr)->getSlice()->getPPS()->getLoopFilterAcrossTilesEnabledFlag();
390
391  {
392    TComDataCU* ctuCurr  = getCtu(ctuRsAddr);
393    TComDataCU* ctuLeft  = isLeftAvail ?getCtu(ctuRsAddr-1):NULL;
394    TComDataCU* ctuRight = isRightAvail?getCtu(ctuRsAddr+1):NULL;
395    TComDataCU* ctuAbove = isAboveAvail?getCtu(ctuRsAddr-m_frameWidthInCtus):NULL;
396    TComDataCU* ctuBelow = isBelowAvail?getCtu(ctuRsAddr+m_frameWidthInCtus):NULL;
397    TComDataCU* ctuAboveLeft  = isAboveLeftAvail ? getCtu(ctuRsAddr-m_frameWidthInCtus-1):NULL;
398    TComDataCU* ctuAboveRight = isAboveRightAvail? getCtu(ctuRsAddr-m_frameWidthInCtus+1):NULL;
399    TComDataCU* ctuBelowLeft  = isBelowLeftAvail ? getCtu(ctuRsAddr+m_frameWidthInCtus-1):NULL;
400    TComDataCU* ctuBelowRight = isBelowRightAvail? getCtu(ctuRsAddr+m_frameWidthInCtus+1):NULL;
401
402    {
403      //left
404      if(ctuLeft != NULL)
405      {
406        isLeftAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuLeft->getSlice()->getSliceCurStartCtuTsAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true;
407      }
408      //above
409      if(ctuAbove != NULL)
410      {
411        isAboveAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuAbove->getSlice()->getSliceCurStartCtuTsAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true;
412      }
413      //right
414      if(ctuRight != NULL)
415      {
416        isRightAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuRight->getSlice()->getSliceCurStartCtuTsAddr())?ctuRight->getSlice()->getLFCrossSliceBoundaryFlag():true;
417      }
418      //below
419      if(ctuBelow != NULL)
420      {
421        isBelowAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuBelow->getSlice()->getSliceCurStartCtuTsAddr())?ctuBelow->getSlice()->getLFCrossSliceBoundaryFlag():true;
422      }
423      //above-left
424      if(ctuAboveLeft != NULL)
425      {
426        isAboveLeftAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuAboveLeft->getSlice()->getSliceCurStartCtuTsAddr())?ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag():true;
427      }
428      //below-right
429      if(ctuBelowRight != NULL)
430      {
431        isBelowRightAvail = (ctuCurr->getSlice()->getSliceCurStartCtuTsAddr() != ctuBelowRight->getSlice()->getSliceCurStartCtuTsAddr())?ctuBelowRight->getSlice()->getLFCrossSliceBoundaryFlag():true;
432      }
433
434      //above-right
435      if(ctuAboveRight != NULL)
436      {
437        Int curSliceStartTsAddr  = ctuCurr->getSlice()->getSliceCurStartCtuTsAddr();
438        Int aboveRightSliceStartTsAddr = ctuAboveRight->getSlice()->getSliceCurStartCtuTsAddr();
439
440        isAboveRightAvail = (curSliceStartTsAddr == aboveRightSliceStartTsAddr)?(true):
441          (
442          (curSliceStartTsAddr > aboveRightSliceStartTsAddr)?(ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag())
443          :(ctuAboveRight->getSlice()->getLFCrossSliceBoundaryFlag())
444          );
445      }
446      //below-left
447      if(ctuBelowLeft != NULL)
448      {
449        Int curSliceStartTsAddr       = ctuCurr->getSlice()->getSliceCurStartCtuTsAddr();
450        Int belowLeftSliceStartTsAddr = ctuBelowLeft->getSlice()->getSliceCurStartCtuTsAddr();
451
452        isBelowLeftAvail = (curSliceStartTsAddr == belowLeftSliceStartTsAddr)?(true):
453          (
454          (curSliceStartTsAddr > belowLeftSliceStartTsAddr)?(ctuCurr->getSlice()->getLFCrossSliceBoundaryFlag())
455          :(ctuBelowLeft->getSlice()->getLFCrossSliceBoundaryFlag())
456          );
457      }
458    }
459
460    if(!isLoopFiltAcrossTilePPS)
461    {
462      isLeftAvail      = (!isLeftAvail      ) ?false:(getTileIdxMap( ctuLeft->getCtuRsAddr()         ) == getTileIdxMap( ctuRsAddr ));
463      isAboveAvail     = (!isAboveAvail     ) ?false:(getTileIdxMap( ctuAbove->getCtuRsAddr()        ) == getTileIdxMap( ctuRsAddr ));
464      isRightAvail     = (!isRightAvail     ) ?false:(getTileIdxMap( ctuRight->getCtuRsAddr()        ) == getTileIdxMap( ctuRsAddr ));
465      isBelowAvail     = (!isBelowAvail     ) ?false:(getTileIdxMap( ctuBelow->getCtuRsAddr()        ) == getTileIdxMap( ctuRsAddr ));
466      isAboveLeftAvail = (!isAboveLeftAvail ) ?false:(getTileIdxMap( ctuAboveLeft->getCtuRsAddr()    ) == getTileIdxMap( ctuRsAddr ));
467      isAboveRightAvail= (!isAboveRightAvail) ?false:(getTileIdxMap( ctuAboveRight->getCtuRsAddr()   ) == getTileIdxMap( ctuRsAddr ));
468      isBelowLeftAvail = (!isBelowLeftAvail ) ?false:(getTileIdxMap( ctuBelowLeft->getCtuRsAddr()    ) == getTileIdxMap( ctuRsAddr ));
469      isBelowRightAvail= (!isBelowRightAvail) ?false:(getTileIdxMap( ctuBelowRight->getCtuRsAddr()   ) == getTileIdxMap( ctuRsAddr ));
470    }
471  }
472
473}
474
475
476TComTile::TComTile()
477: m_tileWidthInCtus     (0)
478, m_tileHeightInCtus    (0)
479, m_rightEdgePosInCtus  (0)
480, m_bottomEdgePosInCtus (0)
481, m_firstCtuRsAddr      (0)
482{
483}
484
485TComTile::~TComTile()
486{
487}
488//! \}
Note: See TracBrowser for help on using the repository browser.